<?php

if (!function_exists('array_save'))
{
    /**
     * 保存数组
     */
    function array_save($aValue, $sFile, $sVar = false)
    {
        $sValue = var_export($aValue, true);
        $sValue = !$sVar
            ? sprintf('<?php return %s; ', $sValue)
            : sprintf('<?php %s = %s;', $sVar, $sValue);
        file_put_contents($sFile, $sValue);
    }
}

class PhpPDFLib extends \PDFlib
{
    public function __construct(){
        parent::__construct();
    }

    public function addTableCell($cell, $col, $run, $value, $option){
        try{
            return parent::add_table_cell($cell, $col, $run, $value, $option);
        }catch(\Exception $e){
            dump($cell, $col, $run, $value, $option);
            throw new \Exception ( $e );
        }
    }
    
    public function loadImage($type, $value, $option){
        try{
            if(!file_exists($value)){
                throw new \Exception ( $value.' 图片不存在' );
            }
            return parent::load_image($type, $value, $option);
        }catch(\Exception $e){
            dump($type, $value, $option);
            throw new \Exception ( $e );
        }
    }
} 

/**
 * 成品目录
 */
class Catalog
{
    // 配置
    public $aOption;
    
    // 数据
    public $aCatalog;
    
    public function __construct($aOption = [], $aCatalog = [])
    {
        //array_save($aOption, __DIR__. '/option.php');
        //array_save($aCatalog, __DIR__. '/data.php');

        // 超大内存
        set_time_limit(0);
        //ini_set('memory_limit', '32G');

        $this->aCatalog = $aCatalog;
        $this->aOption = [
            // 选择版式
            'style' => 'default',
            // 备注
            'remark' => '',
            
            'color' => 'blue',
            
            // 文件名称
            'name' => sprintf('browser_%s.pdf', time()),
            // 存放目录
            'path' => sprintf('%s/storage/pdf', __DIR__),
            
            // 是否浏览器调试模式
            'browser' => true,
            // 资源目录
            'resources' => sprintf('%s/storage', __DIR__),
            
            // A4纸边框距离
            'point' => [
                'x1' => 38, // 左1.3cm
                'y1' => 43, // 下1.5cm
                'x2' => 563, // 右1.1cm
                'y2' => 813, // 上1cm
            ],
        ];
        
        if ($aOption) {
            $this->aOption = array_merge($this->aOption, $aOption);
        }
        $this->aOption['ver'] = ($this->aOption['color'] == 'blue') ? 'GSP' : 'G-AP';
        $this->aOption['gTitle'] = sprintf('%s Ref.', $this->aOption['ver']);

        $this->aOption['image'] = [
            'brake' => sprintf('%s/image/%s/wheelBrake.jpg', $this->aOption['resources'], $this->aOption['color']),
            'hubAssemblies1' => sprintf('%s/image/%s/wheelHubAssemblies1.jpg', $this->aOption['resources'], $this->aOption['color']),
            'hubAssemblies2' => sprintf('%s/image/%s/wheelHubAssemblies2.jpg', $this->aOption['resources'], $this->aOption['color']),
            'driveShaft' => sprintf('%s/image/%s/wheelDriveShaft.jpg', $this->aOption['resources'], $this->aOption['color']),
            'bearingKits1' => sprintf('%s/image/%s/wheelBearingKits1.jpg', $this->aOption['resources'], $this->aOption['color']),
            'bearingKits2' => sprintf('%s/image/%s/wheelBearingKits2.jpg', $this->aOption['resources'], $this->aOption['color']),
            'propellerShaftByDrive1' => sprintf('%s/image/%s/propellerShaftByDrive1.png', $this->aOption['resources'], $this->aOption['color']),
            'propellerShaftByDrive2' => sprintf('%s/image/%s/propellerShaftByDrive2.jpg', $this->aOption['resources'], $this->aOption['color']),
            'tensionerByBearing' => sprintf('%s/image/%s/tensionerByBearing.png', $this->aOption['resources'], $this->aOption['color']),
            'clutchByBearing' => sprintf('%s/image/%s/clutchByBearing.png', $this->aOption['resources'], $this->aOption['color']),
            'stubAxle1' => sprintf('%s/image/%s/stubAxle1.jpg', $this->aOption['resources'], $this->aOption['color']),
            'stubAxle2' => sprintf('%s/image/%s/stubAxle2.jpg', $this->aOption['resources'], $this->aOption['color']),
        ];

        $aColor = [
            'red' => [
                'font' => '#FF0000',
                'line' => '#BF0000',
                'back' => '#ECB6B6',
                'other' => '#BFBFBF',
				'title' => '#FF0000',
            ],

            'blue' => [
                'font' => '#003366',
                'line' => '#004481',
                'back' => '#DCEBF5',
                'other' => '#BFBFBF',
				'title' => '#000000',
            ],
        ];
        $this->aOption['colors'] = array_merge($aColor[$this->aOption['color']], [
            'white' => '#FFFFFF',
            'black' => '#000000',
            'blue' => '#004C99',
			'red' => '#FF0000',
        ]);
    }
    
    /**
     * PDFlib
     *
     * @return PDFlib
     */
    public function init(): PDFlib
    {
		$oCatalog = null;
        $sLicense = dirname(__FILE__). '/license.txt';

        // 资源
        $sSearch = sprintf('SearchPath={{%s}}', $this->aOption['resources']);
        
        // 初始化对象
        try
        {
            $oCatalog = new PhpPDFlib();
            $oCatalog->set_option('charref=true');
            //$oCatalog->set_option('textformat=utf8');
            $oCatalog->set_option('stringformat=utf8');
            $oCatalog->set_option('errorpolicy=return');
            if (is_file($sLicense)) {
                $oCatalog->set_option("license=".file_get_contents($sLicense));
            }
            $oCatalog->set_option($sSearch);
        } catch (PDFlibException $oException) {
            var_dump($oException->get_errnum(), $oException->get_apiname(), $oException->get_errmsg()); exit;
        }
        
        // 字体资源
        $this->aOption['font'] = [
            // 常规
            'arial' => $oCatalog->load_font($this->aOption['fonts']['arial'] ?? 'font/arial', 'unicode', 'embedding'),
            // 粗体
            'arial_bd' => $oCatalog->load_font($this->aOption['fonts']['arial_bd'] ?? 'font/arial_bd', 'unicode', 'embedding'),
            // 黑体
            'arial_black' => $oCatalog->load_font($this->aOption['fonts']['arial_black'] ?? 'font/arial_black', 'unicode', 'embedding'),
        ];
        
        // 初始化页码
        $this->aOption['pagination'] = 1;
        return $oCatalog;
    }
    
    /**
     * 执行
     */
    public function run()
    {
        // 生成页码
        // 调试某块版式的时候, 设置debug为FALSE
        # 595 842
        $aCatalog = [];
        $aMethod = ['vehicleGuide', 'vehicle1Guide'];
        if ($this->aOption['debug'] && $this->aOption['compute'])
        {
            $aVehicle = [];
            foreach ($this->aOption['compute'] as $sSetup)
            {
                if (!isset($this->aCatalog[$sSetup])) {
                    continue;
                }
                
                if ((false === in_array($this->aCatalog[$sSetup]['style'], $aMethod)) && (!isset($this->aCatalog[$sSetup]['value']) || !$this->aCatalog[$sSetup]['value'])) {
                    continue;
                }
                
                $sPagination = 0;
                $oCatalog = $this->init();
                $oCatalog->begin_document('', '');
                $sCatalog = $this->aCatalog[$sSetup]['catalog'] ?? 'default';
                switch ($this->aCatalog[$sSetup]['style'])
                {
                    case 'vehicleGuide':
                    case 'vehicle1Guide':
                        if ($aVehicle)
                        {
                            $this->aCatalog[$sSetup]['value'] = $aVehicle[$sCatalog]['vehicle'];
                            $this->aCatalog[$sSetup]['redirect'] = $aVehicle[$sCatalog]['redirect'];
                            $sPagination = $this->{$this->aCatalog[$sSetup]['style']}($oCatalog, $this->aCatalog[$sSetup], true);
                        }
                        break;
                    
                    case 'brakeByWheel':
                    case 'hubAssembliesByWheel':
                        $sPagination = $this->hubAssembliesByWheel($oCatalog, $this->aCatalog[$sSetup], true);
                        break;
                    
                    case 'clutchByBearing':
                    case 'tensionerByBearing':
                        $sPagination = $this->clutchByBearing($oCatalog, $this->aCatalog[$sSetup], true);
                        break;
                    
                    case 'modelGuideByWheel':
                    case 'modelGuideByWaterPump':
                    case 'modelGuideByShockAbsorber':
                    case 'modelGuideByPropShaft':
                    case 'modelGuideByPropShaftAssembly':
                    case 'modelGuideBySuspension':
                    case 'modelGuideBySensor':
                    case 'modelGuideByDrive':
                    case 'modelGuideByBearing':
                        $aModel = $this->{$this->aCatalog[$sSetup]['style']}($oCatalog, $this->aCatalog[$sSetup], true);
                        $aVehicle[$sCatalog] = ['vehicle' => $aModel['vehicle'], 'redirect' => $sSetup];
                        $sPagination = $aModel['pagination'];
                        break;
                    
                    case 'photoGuideByWheel':
                    case 'photoGuideByWaterPump':
                    case 'photoGuideBySuspension':
                        // 图片+？
                        $sPagination = $this->{$this->aCatalog[$sSetup]['style']}($oCatalog, $this->aCatalog[$sSetup], true);
                        break;
                    
                    case 'photoGuideByBearing':
                    case 'photoGuideByTensioner':
                        $sPagination = $this->photoGuideByBearing($oCatalog, $this->aCatalog[$sSetup], true);
                        break;
                    
                    case 'remarkGuide':
                        $oCatalog->begin_page_ext(0, 0, 'width=a4.width height=a4.height');
                        $oCatalog->end_page_ext('');
                        
                        $sPagination = count($this->aCatalog[$sSetup]['value']['imglist']);
                        break;
                    
                    default:
                        $sPagination = $this->{$this->aCatalog[$sSetup]['style']}($oCatalog, $this->aCatalog[$sSetup], true);
                        break;
                }
                
                $aPagination = [
                    'compute' => $this->aCatalog[$sSetup]['compute'] ?? false,
                    'style' => $this->aCatalog[$sSetup]['style'],
                    'value' => $this->aCatalog[$sSetup]['remark'],
                    'pagination' => $sPagination,
                ];
                if (false !== in_array($this->aCatalog[$sSetup]['style'], $aMethod))
                {
                    $aCatalog[$sCatalog] = $aCatalog[$sCatalog] ?? [];
                    $aCatalog[$sCatalog] = array_merge([$sSetup => $aPagination], $aCatalog[$sCatalog]);
                } else
                {
                    $aCatalog[$sCatalog][$sSetup] = $aPagination;
                }
                $oCatalog->end_document('');
                unset($oCatalog);
            }
        }

        // 生成总索引页码
        if ($aCatalog)
        {
            $aImage = [];
            $aPhoto = [];
            $aValue = [];
            $sValue = false;
            $aRunAr = ['s' => 1, 'e' => 0];
            foreach ($this->aOption['setup'] as $sSetup)
            {
                $sCatalog = $this->aCatalog[$sSetup]['catalog'] ?? 'default';
                if (!isset($aCatalog[$sCatalog][$sSetup])) {
                    continue;
                }

                if (false === in_array($aCatalog[$sCatalog][$sSetup]['style'], $aMethod))
                {
                    if ($sValue) {
                        $aRunAr['s'] = $aRunAr['e'] + 1;
                    }
    
                    $aRunAr['e'] = $aCatalog[$sCatalog][$sSetup]['pagination'] + $aRunAr['e'];
                    $aValue[$sCatalog][$sSetup] = array_merge($aCatalog[$sCatalog][$sSetup], [
                        'start' => $aRunAr['s'], 'end' => $aRunAr['e']
                    ]);
                    $sValue = true;
                } else
                {
                    // 车型索引页使用罗马数字
                    $aValue[$sCatalog][$sSetup] = array_merge($aCatalog[$sCatalog][$sSetup], [
                        'start' => $this->decToRoman(1), 'end' => $this->decToRoman($aCatalog[$sCatalog][$sSetup]['pagination'])
                    ]);
                }
                
                // 判断连续图片, 合并到一起
                if ('photo' == substr($aValue[$sCatalog][$sSetup]['style'], 0, 5))
                {
                    if ($aImage) {
                        $aImage[$sCatalog]['end'] = $aValue[$sCatalog][$sSetup]['end'];
                    } else {
                        $aImage = [$sCatalog => ['start' => $aValue[$sCatalog][$sSetup]['start'], 'end' => $aValue[$sCatalog][$sSetup]['end']]];
                    }
                    
                    if ($aPhoto && (($aPhoto[$sCatalog]['end'] + 1) == $aValue[$sCatalog][$sSetup]['start']))
                    {
                        $aPhoto[$sCatalog]['end'] = $aValue[$sCatalog][$sSetup]['end'];
                        $aPhoto[$sCatalog]['lists'][] = $sSetup;
                    } else
                    {
                        $aPhoto = [];
                        $aPhoto[$sCatalog] = array_merge($aValue[$sCatalog][$sSetup], ['lists' => [$sSetup]]);
                    }
                }
            }
    
            // 判断连续图片, 合并到一起
            if ($aImage)
            {
                foreach ($aPhoto as $sKey => $aVal)
                {
                    if (($aImage[$sKey]['start'] != $aVal['start']) || ($aImage[$sKey]['end'] != $aVal['end'])) {
                        continue;
                    }
                    
                    foreach ($aVal['lists'] as $sKKK => $sVVV)
                    {
                        if ($sKKK) {
                            unset($aValue[$sKey][$sVVV]);
                        } else {
                            $aValue[$sKey][$sVVV] = $aVal;
                        }
                    }
                }
            }
            
            // 将索引压入总索引
            foreach ($this->aOption['setup'] as $sSetup)
            {
                switch ($this->aCatalog[$sSetup]['style'])
                {
                    case 'generalGuide':
                    case 'generalGuideMore':
                        $this->aCatalog[$sSetup]['value'] = $aValue;
                        break;
                    
                    case 'vehicleGuide':
                    case 'vehicle1Guide':
                        $sCatalog = $this->aCatalog[$sSetup]['catalog'] ?? 'default';
                        foreach ($this->aCatalog[$sSetup]['value'] as $sKey => $aVal) {
                            $this->aCatalog[$sSetup]['value'][$sKey]['page'] += $aValue[$sCatalog][$this->aCatalog[$sSetup]['redirect']]['start'] - 1;
                        }
                        break;
                }
            }
        }
        
        // 顺序生成目录
        $oCatalog = $this->init();
        $oCatalog->set_info('Title', $this->aOption['remark']);
        $oCatalog->begin_document('', '');
        foreach ($this->aOption['setup'] as $sSetup)
        {
            if (!isset($this->aCatalog[$sSetup]['value']) || !$this->aCatalog[$sSetup]['value']) {
                continue;
            }
            
            switch ($this->aCatalog[$sSetup]['style'])
            {
                case 'brakeByWheel':
                case 'hubAssembliesByWheel':
                    $oCatalog = $this->hubAssembliesByWheel($oCatalog, $this->aCatalog[$sSetup]);
                    break;
                
                case 'clutchByBearing':
                case 'tensionerByBearing':
                    $oCatalog = $this->clutchByBearing($oCatalog, $this->aCatalog[$sSetup]);
                    break;
                
                case 'photoGuideByBearing':
                case 'photoGuideByTensioner':
                    $oCatalog = $this->photoGuideByBearing($oCatalog, $this->aCatalog[$sSetup]);
                    break;
                
                default:
                    $oCatalog = $this->{$this->aCatalog[$sSetup]['style']}($oCatalog, $this->aCatalog[$sSetup]);
                    break;
            }
        }
        $oCatalog->end_document('');
        return $this->browser($oCatalog, $this->aOption['browser']);
    }

    /**
     * 宣传页
     */
    public function leaflet(PDFlib $oCatalog, array $aValue, bool $sBuffer = false)
    {
        $aPoint = [
            'x1' => 42, // 左1cm // 28
            'y1' => 70, // 下1.3cm
            'x2' => 553, // 右1.1cm // 567
            'y2' => 772, // 上2.4cm

            // 页码
            'headerX1' => 525,
            'headerY1' => 814,

            // banner
            'bannerHeight' => 63,
            'bannerTitleWidth' => 511, //359,

            // banner logo
            'bannerImageWidth' => 90,
            'bannerImageHeight' => 28,

            // model
            'modelHeight' => 288,
            'modelCellHeight' => 220,
            'modelOtherHeight' => 34,

            // title
            'titleHeight' => 27,

            // 内容
            'cellWidth1' => 63, // 第一列的宽度 -2
            'cellWidth2' => 93, // 第二列的宽度 -9
            'cellWidth3' => 106, // -10
            'cellWidth4' => 68, // -2
            'cellWidth5' => 104, // -9
            'cellWidth6' => 77, // -3

            'cellHeight' => 54, // 表格高度
        ];
        $aPoint['cellWidth'] = $aPoint['x2'] - $aPoint['x1'];

        $aModel = $aValue['value'];
        $aValue = $aModel['value'];
        unset($aModel['value']);

        // 计算页码
        $sCount = count($aValue);
        $aTotal = ['total' => 1, 'odd' => $sCount % 6];
        if ($sCount > 6)
        {
            $aTotal = [
                'odd' => ($sCount - 6) % 12,
                'total' => ceil(($sCount - 6) / 12) + 1,
            ];
        }

        $sRow = 1;
        $sCell = 0;
        $sPage = 1;
        $sOther = 0;
        $sWhile = true;
        $aMatch = [1 => 'GSP NO.', 'Description', 'Fitting Position', 'OE NO.', 'REMARKS', 'Picture'];
        while ($sWhile)
        {
            if ($sRow == 1)
            {
                $sRaw = ($sPage == 1) ? 7 : 13;
                $oCatalog->begin_page_ext(0, 0, 'width=a4.width height=a4.height');
                $oCatalog->setcolor("fill", "cmyk", 100/100, 65/100, 0, 15/100);
                $oCatalog->rect(0, 0, 595, 842);
                $oCatalog->fill();

                // 背景图
                if (isset($aModel['background']) && is_file($aModel['background']))
                {
                    // 判断使用那张底图
                    // 产品推荐铺满使用 "background", 如有空位则显示 "background_end"
                    $background = $aModel['background'];
                    if (($sPage == $aTotal['total']) && $aTotal['odd']) {
                        $background = $aModel['background_end'];
                    }

                    $oImage = $oCatalog->loadImage('auto', $background, '');
                    $oCatalog->fit_image($oImage, 0, 0, "");
                    $oCatalog->close_image($oImage);
                }

                if ($sPage == 1)
                {
                    // banner logo
                    $sCell = 0;
                    $oImage = $oCatalog->loadImage('auto', $aModel['banner']['image'], '');
                    $sOption = 'colwidth=%s rowheight=%s image=%s fitimage={position={center}}';
                    $sOption = sprintf($sOption, $aPoint['bannerImageWidth'], $aPoint['bannerImageHeight'], $oImage);
                    $sCell = $oCatalog->addTableCell($sCell, 1, 1, '', $sOption);

                    $headerY2 = $aPoint['headerY1'] + 8;
                    $headerY1 = $headerY2 - $aPoint['bannerImageHeight'];
                    $sOption = 'header=0 rowheightdefault=auto fitmethod=nofit stroke={{line=other linewidth=0}}';
                    $oCatalog->fit_table($sCell, $aPoint['x1'], $headerY1, $aPoint['x1'] + $aPoint['bannerImageWidth'], $headerY2, $sOption);

                    // 页码
                    $sOption = 'fontname=font/arial embedding encoding=unicode fontsize=12 fillcolor=%s';
                    $sOption = sprintf($sOption, $this->aOption['colors']['white']);
                    $oCatalog->fit_textline($aModel['code'], $aPoint['headerX1'], $aPoint['headerY1'], $sOption);

                    // 标题头
                    $sCell = 0;
                    $sOption = 'colwidth=%s rowheight=%s fittextline={font=%s fontsize=36 fillcolor=%s fitmethod=auto position={center}}';
                    $sOption = sprintf($sOption, $aPoint['bannerTitleWidth'], $aPoint['bannerHeight'], $this->aOption['font']['arial_bd'], $aModel['banner']['fill'] ?? $this->aOption['colors']['white']);
                    $sCell = $oCatalog->addTableCell($sCell, 1, 1, $aModel['banner']['title'], $sOption);

                    $sOption = 'header=0 rowheightdefault=auto fitmethod=nofit stroke={{line=other linewidth=0}}';
                    $oCatalog->fit_table($sCell, $aPoint['x1'], $aPoint['y2'] - $aPoint['modelHeight'] - 8, $aPoint['x2'], $aPoint['y2'] - 8, $sOption);

                    // 车型导航
                    $sCell = 0;
                    for ($sRun = 1; $sRun <= 3; $sRun ++)
                    {
                        switch ($sRun)
                        {
                            case 2:
                                $sValue = '';
                                $oImage = $oCatalog->loadImage('auto', $aModel['model']['image'], '');
                                $sOption = 'colwidth=%s rowheight=%s image=%s fitimage={position={center}}';
                                $sOption = sprintf($sOption, $aPoint['cellWidth'], $aPoint['modelCellHeight'], $oImage);
                                break;

                            default:
                                $sValue = ($sRun == 3) ? $aModel['model']['title'] : '';
                                $sOption = 'colwidth=%s rowheight=%s fittextline={font=%s fontsize=14 fillcolor=%s fitmethod=auto position={center}} marginbottom=3';
                                $sOption = sprintf($sOption, $aPoint['cellWidth'], $aPoint['modelOtherHeight'], $this->aOption['font']['arial_bd'], $aModel['model']['fill'] ?? $this->aOption['colors']['white']);
                                break;
                        }
                        $sCell = $oCatalog->addTableCell($sCell, 1, $sRun, $sValue, $sOption);
                    }
                    $sOption = 'header=0 rowheightdefault=auto fitmethod=nofit stroke={{line=other linewidth=0}}';
                    $oCatalog->fit_table($sCell, $aPoint['x1'], $aPoint['y2'] - $aPoint['bannerHeight'] - $aPoint['modelHeight'] + 14, $aPoint['x2'], $aPoint['y2'] - $aPoint['bannerHeight'] + 14, $sOption);

                    $sOther = $aPoint['bannerHeight'] + $aPoint['modelHeight'];
                }

                // 表格头
                $sCell = 0;
                for ($sCol = 1; $sCol <= 6; $sCol ++)
                {
                    $sOption = 'colwidth=%s rowheight=%s fittextline={font=%s fontsize=12 fillcolor=%s fitmethod=auto position={center}} matchbox={fillcolor=%s}';
                    $sOption = sprintf($sOption, $aPoint[sprintf('cellWidth%d', $sCol)], $aPoint['titleHeight'], $this->aOption['font']['arial_bd'], $aModel['table']['fill'] ?? '#263765', $aModel['table']['background'] ?? $this->aOption['colors']['blue']);
                    $sCell = $oCatalog->addTableCell($sCell, $sCol, $sRow, $aMatch[$sCol], $sOption);
                }
                $sRow ++;
                $sPage ++;
            }

            $aShift = array_shift($aValue);
            for ($sCol = 1; $sCol <= 6; $sCol ++)
            {
                $sStr = '';
                switch ($sCol)
                {
                    case 6:
                        $oImage = $oCatalog->loadImage('auto', $aShift['col6'], '');
                        $sOption = 'colwidth=%s rowheight=%s image=%s fitimage={position={center}} margin=3';
                        $sOption = sprintf($sOption, $aPoint['cellWidth6'], $aPoint['cellHeight'], $oImage);
                        break;

                    case 1:
                    case 4:
                        $sStr = $aShift[sprintf('col%d', $sCol)];
                        $sOption = 'colwidth=%s rowheight=%s fittextline={font=%s fillcolor=%s fontsize=10 fitmethod=auto position={center}}  margin=5';
                        $sOption = sprintf($sOption, $aPoint[sprintf('cellWidth%d', $sCol)], $aPoint['cellHeight'], $this->aOption['font']['arial'], $aModel['fill'] ?? $this->aOption['colors']['white']);
                        break;

                    default:
                        $sFont = 10;
                        $sValue = $aShift[sprintf('col%d', $sCol)];
                        $sLen = mb_strlen($sValue);
                        if ($sLen > 50) {
                            $sFont = 8;
                        }
                        if ($sLen > 100) {
                            $sFont = 7;
                        }
                        if ($sLen > 140) {
                            $sFont = 6;
                        }
                        if ($sLen > 200) {
                            $sFont = 5;
                        }
                        if ($sLen > 320) {
                            $sFont = 4;
                        }

                        $sChild = 0;
                        $sOption = 'fontname=font/arial encoding=unicode fontsize=%s fillcolor=%s lastalignment=center alignment=center charref=true avoidemptybegin=true';
                        $sOption = sprintf($sOption, $sFont, $aModel['fill'] ?? $this->aOption['colors']['white']);
                        $sChild = $oCatalog->add_textflow($sChild, $sValue, $sOption);

                        $sOption = 'colwidth=%s rowheight=%s fittextline={font=%s fontsize=10 fitmethod=auto position={center}} textflow=%s fittextflow={verticalalign=center} margin=2';
                        $sOption = sprintf($sOption, $aPoint[sprintf('cellWidth%d', $sCol)], $aPoint['cellHeight'], $this->aOption['font']['arial'], $sChild);
                        break;
                }
                $sCell = $oCatalog->addTableCell($sCell, $sCol, $sRow, $sStr, $sOption);
            }
            $sRow ++;

            // 页面结束
            if (($sRow > $sRaw) || !$aValue)
            {
                $sOption = 'header=0 rowheightdefault=auto fitmethod=nofit stroke={{line=other linewidth=2 strokecolor=%s}}';
                $sOption = sprintf($sOption, $this->aOption['colors']['white']);
                $oCatalog->fit_table($sCell, $aPoint['x1'], $aValue ? $aPoint['y1'] : $aPoint['y1'] + $aPoint['cellHeight'], $aPoint['x2'], $sOther ? ($aPoint['y2'] - $sOther) : $aPoint['y2'], $sOption);

                if (!$aValue)
                {
                    $sWhile = false;

                    // 生成logo结尾
                    if ($sRow <= $sRaw)
                    {
                        $sLogo = 0;
                        $oImage = $oCatalog->loadImage('auto', $aModel['logo']['image'], '');
                        $sOption = 'colwidth=%s rowheight=%s image=%s fitimage={position={center}} margin=5';
                        $sOption = sprintf($sOption, $aPoint['cellWidth'], $aPoint['cellHeight'], $oImage);
                        $sLogo = $oCatalog->addTableCell($sLogo, 1, 1, '', $sOption);

                        $sOption = 'header=0 rowheightdefault=auto fitmethod=nofit stroke={{line=other linewidth=0}}';
                        $oCatalog->fit_table($sLogo, $aPoint['x1'], $aPoint['y1'], $aPoint['x2'], $aPoint['y1'], $sOption);
                    }
                }

                $sRow = 1;
                $sOther = 0;
                $oCatalog->end_page_ext('');
            }
        }

        return $oCatalog;
    }

    /**
     * 单分组目录索引
     *
     * @param PDFlib $oCatalog
     * @param array $aValue  数据
     *
     * @example [
     *       style' => 'generalGuide',
     *      'title' => 'GENERAL INDEX',
     *      'remark' => 'GENERAL INDEX',
     *      'addon' => [
     *          'fontsize' => 14, // 字体大小
     *          'leftMargin' => 32, // 左侧到线距离
     *          'lineHeight' => 32, // 行高
     *      ],
     *      'value' => [
     *          'default' => [
     *              ['value' => '标题', 'start' => '开始页码', 'end' => '结束页码'],
     *              ...
     *          ]
     *      ],
     * ]
     *
     * @return PDFlib
     */
    public function generalGuide(PDFlib $oCatalog, array $aValue): PDFlib
    {
        // 设置默认值
        $aMerge = [
            'fontsize' => 14,
            'lineHeight' => 32,
            'leftMargin' => 32,
            'contentWidth' => 360,
        ];
        $aAddon = $aValue['addon'] ?? [];
        $aAddon = $aAddon ? array_merge($aMerge, $aAddon) : $aMerge;

        $aValue = $aValue['value'] ?? [];
        $aValue = $aValue ? array_shift($aValue) : [];
        if ($aValue)
        {
            $oCatalog->begin_page_ext(0, 0, 'width=a4.width height=a4.height');
            $oCatalog->create_bookmark('GENERAL INDEX', sprintf('parent=%d', 0));
            $aPoint = [
                'x1' => $this->aOption['point']['x1'] + $aAddon['leftMargin'],
                'y1' => 680,
                
                'cellWidth' => $aAddon['contentWidth'],
                'cellEmptyWidth' => 15,
                'cellHeight' => $aAddon['lineHeight'],
            ];
            
            $sResult = 0;
            $sOption = 'colwidth=%s rowheight=%s fittextline={font=%s fontsize=14 fillcolor=%s}';
            $sOption = sprintf($sOption, $this->aOption['point']['x2'] - $this->aOption['point']['x1'], 60, $this->aOption['font']['arial_bd'], $this->aOption['colors']['font']);
            $sResult = $oCatalog->addTableCell($sResult, 1, 1, 'GENERAL INDEX', $sOption);
            
            $sOption = 'header=0 rowheightdefault=auto stroke={{line=other linewidth=0}}';
            $oCatalog->fit_table($sResult, $this->aOption['point']['x1'], $this->aOption['point']['y2'] - 60, $this->aOption['point']['x2'], $this->aOption['point']['y2'], $sOption);
            
            $sQuery = sprintf('fontname=font/arial_bd embedding encoding=unicode fontsize=%d boxsize={%d 30} fitmethod=auto leader={alignment=right}', $aAddon['fontsize'], $aPoint['cellWidth']);
            $sChild = sprintf('fontname=font/arial_bd embedding encoding=unicode fontsize=%d', $aAddon['fontsize']);
            foreach ($aValue as $aVal)
            {
                if (!isset($aVal['compute']) || !$aVal['compute']) {
                    continue;
                }

                if (filter_var($aVal['start'], FILTER_VALIDATE_INT) && (strlen($aVal['start']) < 3)) {
                    $aVal['start'] = str_pad($aVal['start'], 3, '0', STR_PAD_LEFT);
                }
                
                if (filter_var($aVal['end'], FILTER_VALIDATE_INT) && (strlen($aVal['end']) < 3)) {
                    $aVal['end'] = str_pad($aVal['end'], 3, '0', STR_PAD_LEFT);
                }

                /*
                $sPagination = ($aVal['start'] != $aVal['end'])
                    ? sprintf('page.%s-%s', $aVal['start'], $aVal['end'])
                    : sprintf('page.%s', $aVal['start']);
                */
                $sPagination = sprintf('page.%s-%s', $aVal['start'], $aVal['end']);
                $oCatalog->fit_textline($aVal['value'], $aPoint['x1'], $aPoint['y1'] -= $aPoint['cellHeight'], $sQuery);
                $oCatalog->fit_textline('...', $aPoint['x1'] + $aPoint['cellWidth'], $aPoint['y1'], $sChild);
                $oCatalog->fit_textline($sPagination, $aPoint['x1'] + $aPoint['cellWidth'] + $aPoint['cellEmptyWidth'], $aPoint['y1'], $sChild);
            }

            $sResult = 0;
            $sOption = 'fittextline={font=%s fontsize=9 fitmethod=auto fillcolor=%s}';
            $sOption = sprintf($sOption, $this->aOption['font']['arial_bd'], $this->aOption['colors']['font']);
            $sResult = $oCatalog->addTableCell($sResult, 1, 1, '', $sOption);
            
            $sOption = 'header=0 rowheightdefault=auto stroke={{line=other linewidth=1 strokecolor=%s}}';
            $sOption = sprintf($sOption, $this->aOption['colors']['line']);
            $oCatalog->fit_table($sResult, $this->aOption['point']['x1'], $this->aOption['point']['y1'], $this->aOption['point']['x2'], $this->aOption['point']['y2'], $sOption);
            $oCatalog->end_page_ext('');
        }
        
        return $oCatalog;
    }
    
    /**
     * 目录索引
     *
     * @param PDFlib $oCatalog
     * @param array $aValue  数据
     *
     * @example [
     *       style' => 'generalGuide',
     *      'title' => 'GENERAL INDEX',
     *      'remark' => 'GENERAL INDEX',
     *      'addon' => [
     *          'fontsize' => 14, // 字体大小
     *          'leftMargin' => 32, // 左侧到线距离
     *          'lineHeight' => 32, // 行高
     *      ],
     *      'value' => [
     *          'default' => [
     *              ['value' => '标题', 'start' => '开始页码', 'end' => '结束页码'],
     *              ...
     *          ]
     *      ],
     * ]
     *
     * @return PDFlib
     */
    public function generalGuideMore(PDFlib $oCatalog, array $aValue): PDFlib
    {
        // 设置默认值
        $aMerge = [
            'fontsize' => 14,
            'lineHeight' => 32,
            'leftMargin' => 32,
            'contentWidth' => 360,
        ];
        $aAddon = $aValue['addon'] ?? [];
        $aAddon = $aAddon ? array_merge($aMerge, $aAddon) : $aMerge;

        $aValue = $aValue['value'] ?? [];
        $aValue = $aValue ? array_shift($aValue) : [];
        if ($aValue)
        {
            $oCatalog->begin_page_ext(0, 0, 'width=a4.width height=a4.height');
            $oCatalog->create_bookmark('GENERAL INDEX', sprintf('parent=%d', 0));
            $aPoint = [
                'x1' => $this->aOption['point']['x1'] + $aAddon['leftMargin'],
                'y1' => 680,

                'cellWidth' => $aAddon['contentWidth'],
                'cellEmptyWidth' => 15,
                'cellHeight' => $aAddon['lineHeight'],
            ];
            
            $sResult = 0;
            $sOption = 'colwidth=%s rowheight=%s fittextline={font=%s fontsize=14 fitmethod=auto fillcolor=%s}';
            $sOption = sprintf($sOption, $this->aOption['point']['x2'] - $this->aOption['point']['x1'], 60, $this->aOption['font']['arial_bd'], $this->aOption['colors']['font']);
            $sResult = $oCatalog->addTableCell($sResult, 1, 1, 'GENERAL INDEX', $sOption);
            
            $sOption = 'header=0 rowheightdefault=auto stroke={{line=other linewidth=0}}';
            $oCatalog->fit_table($sResult, $this->aOption['point']['x1'], $this->aOption['point']['y2'] - 60, $this->aOption['point']['x2'], $this->aOption['point']['y2'], $sOption);
            
            $sQuery = sprintf('fontname=font/arial_bd embedding encoding=unicode fontsize=%s boxsize={%d 30} fitmethod=auto leader={alignment=right}', $aAddon['fontsize'], $aPoint['cellWidth']);
            $sChild = sprintf('fontname=font/arial_bd embedding encoding=unicode fontsize=%s', $aAddon['fontsize']);
            foreach ($aValue as $aVal)
            {
                if (!isset($aVal['compute']) || !$aVal['compute']) {
                    continue;
                }
                
                if (filter_var($aVal['start'], FILTER_VALIDATE_INT) && (strlen($aVal['start']) < 3)) {
                    $aVal['start'] = str_pad($aVal['start'], 3, '0', STR_PAD_LEFT);
                }
                
                if (filter_var($aVal['end'], FILTER_VALIDATE_INT) && (strlen($aVal['end']) < 3)) {
                    $aVal['end'] = str_pad($aVal['end'], 3, '0', STR_PAD_LEFT);
                }
                
                $sPagination = ($aVal['start'] != $aVal['end'])
                    ? sprintf('page.%s-%s', $aVal['start'], $aVal['end'])
                    : sprintf('page.%s', $aVal['start']);
                $oCatalog->fit_textline($aVal['value'], $aPoint['x1'], $aPoint['y1'] -= $aPoint['cellHeight'], $sQuery);
                $oCatalog->fit_textline('...', $aPoint['x1'] + $aPoint['cellWidth'], $aPoint['y1'], $sChild);
                $oCatalog->fit_textline($sPagination, $aPoint['x1'] + $aPoint['cellWidth'] + $aPoint['cellEmptyWidth'], $aPoint['y1'], $sChild);
            }
            
            $sResult = 0;
            $sOption = 'fittextline={font=%s fontsize=9 fitmethod=auto fillcolor=%s}';
            $sOption = sprintf($sOption, $this->aOption['font']['arial_bd'], $this->aOption['colors']['font']);
            $sResult = $oCatalog->addTableCell($sResult, 1, 1, '', $sOption);
            
            $sOption = sprintf('header=0 rowheightdefault=auto stroke={{line=other linewidth=1 strokecolor=%s}}', $this->aOption['colors']['line']);
            $oCatalog->fit_table($sResult, $this->aOption['point']['x1'], $this->aOption['point']['y1'], $this->aOption['point']['x2'], $this->aOption['point']['y2'], $sOption);
            $oCatalog->end_page_ext('');
        }
        
        return $oCatalog;
    }
    
    /**
     * 车型索引页
     *
     * @param PDFlib $oCatalog
     * @param array $aValue  数据
     * @param false $sBuffer 是否只返回页码
     *
     * @example [
     *      ['make' => '品牌', 'model' => '车系', 'page' => '页码'],
     *      ['make' => 'AUDI', 'model' => 'A3 (8V1, 8VK) 111', 'page' => 1],
     *      ['make' => 'AUDI','model' => 'A3 (8V1, 8VK) 222', 'page' => 1],
     * ]
     *
     * @return int|PDFlib
     */
    public function vehicleGuide(PDFlib $oCatalog, array $aValue, bool $sBuffer = false)
    {
        // 页面内容"最下", "最上"坐标点, 表格宽高
        $aPoint = array_merge($this->aOption['point'], [
            'cellWidth' => 175 , // 表格宽度
            'cellWidth1' => 139, // 表格1宽度
            'cellWidth2' => 36, // 表格2宽度
            'cellHeight' => 10, // 表格高度
        ]);

        // 绘制表格
        $sData = 0;
        $sRemark = $aValue['remark'] ?? '';
        $aValue = $aValue['value'];
        $sSkip = ceil((count($aValue) + count(array_unique(array_column($aValue, 'make')))) / (75 * 3));
        for ($sPage = 1; $sPage <= $sSkip; $sPage ++)
        {
            $sResult = 0;
            $oCatalog->begin_page_ext(0, 0, 'width=a4.width height=a4.height');
            
            if (!$sData && $sRemark)
            {
                $oCatalog->create_bookmark($sRemark, sprintf('parent=%d', 0));
                $sData = 1;
            }
            
            for ($sLine = 1; $sLine <= 3; $sLine ++)
            {
                // 头部加粗
                $sCell = 0;
                $sOption = 'colwidth=%s rowheight=20 fittextline={font=%s fontsize=9 fitmethod=auto fillcolor=%s}';
                $sOption = sprintf($sOption, $aPoint['cellWidth1'], $this->aOption['font']['arial_bd'], $this->aOption['colors']['font']);
                $sCell = $oCatalog->addTableCell($sCell, 1, 1, 'MAKE-MODEL', $sOption);
                
                $sOption = 'colwidth=%s rowheight=20 fittextline={font=%s fontsize=9 fitmethod=auto fillcolor=%s}';
                $sOption = sprintf($sOption, $aPoint['cellWidth2'], $this->aOption['font']['arial_bd'], $this->aOption['colors']['font']);
                $sCell = $oCatalog->addTableCell($sCell, 2, 1, 'PAGE', $sOption);
                
                $sOption = sprintf('header=0 rowheightdefault=auto stroke={{line=other linewidth=1 strokecolor=%s}}', $this->aOption['colors']['line']);
                $oCatalog->fit_table(
                    $sCell,
                    $aPoint['x1']  + ($sLine - 1) * $aPoint['cellWidth'],
                    $aPoint['y2'] - 20,
                    $aPoint['x1'] + $sLine * $aPoint['cellWidth'],
                    $aPoint['y2'],
                    $sOption
                );
                
                // 填充单元格
                if ($aValue)
                {
                    $sCell = 0;
                    $sMake = '';
                    for ($sRow = 1; $sRow <= 75; $sRow ++)
                    {
                        if (!$aValue) {
                            continue;
                        }
                        
                        $aData = array_shift($aValue);
                        if ($sMake != $aData['make'])
                        {
                            $sOption = 'colwidth=%s rowheight=%d fittextline={font=%s fontsize=9 fitmethod=auto position=center} matchbox={fillcolor=%s} colspan=2';
                            $sOption = sprintf($sOption, $aPoint['cellWidth'], $aPoint['cellHeight'], $this->aOption['font']['arial_bd'], ($sRow != 75) ? $this->aOption['colors']['back'] : $this->aOption['colors']['white']);
                            $sCell = $oCatalog->addTableCell($sCell, 1, $sRow, ($sRow != 75) ? $aData['make'] : '', $sOption);

                            if ($sRow == 75) {
                                array_unshift($aValue, $aData);
                            }
                            $sMake = $aData['make'];
                            $sRow ++;
                        }

                        if ($sRow <= 75)
                        {
                            for ($sCol = 1; $sCol <= 2; $sCol ++)
                            {
                                $sData = ($sCol === 1) ? 'model' : 'page';
                                $sAlign = ($sCol === 1) ? 'left' : 'center';
                                $sOption = 'colwidth=%s rowheight=%d fittextline={font=%s fontsize=8 fitmethod=auto position=%s} margin=2';
                                $sOption = sprintf($sOption, $aPoint['cellWidth'. $sCol], $aPoint['cellHeight'], $this->aOption['font']['arial'], $sAlign);
                                $sCell = $oCatalog->addTableCell($sCell, $sCol, $sRow, $aData[$sData], $sOption);
                            }
                        }
                    }
                    
                    $sOption = sprintf('header=0 rowheightdefault=auto stroke={{line=hor0 linewidth=1 strokecolor=%s}}', $this->aOption['colors']['line']);
                    $oCatalog->fit_table(
                        $sCell,
                        $aPoint['x1']  + ($sLine - 1) * $aPoint['cellWidth'],
                        $aPoint['y1'],
                        $aPoint['x1'] + $sLine * $aPoint['cellWidth'],
                        $aPoint['y2'] - 20,
                        $sOption
                    );
                }
                
                $sOption = 'colwidth=%s';
                $sOption = sprintf($sOption, $aPoint['cellWidth'], $this->aOption['font']['arial']);
                $sResult = $oCatalog->addTableCell($sResult, $sLine, 1, '', $sOption);
            }
            $sOption = sprintf('header=0 rowheightdefault=auto stroke={{line=other linewidth=1 strokecolor=%s}}', $this->aOption['colors']['line']);
            $oCatalog->fit_table($sResult, $aPoint['x1'], $aPoint['y1'], $aPoint['x2'], $aPoint['y2'], $sOption);
            $oCatalog = $this->pagination($oCatalog, $this->decToRoman($sPage));
            $oCatalog->end_page_ext('');
        }
        return $sBuffer ? ($sPage - 1) : $oCatalog;
    }
    
    /**
     * 车型索引页
     *
     * @param PDFlib $oCatalog
     * @param array $aValue  数据
     * @param false $sBuffer 是否只返回页码
     *
     * @example [
     *      ['make' => '品牌', 'page' => '页码'],
     *      ['make' => 'AUDI', 'page' => 1],
     *      ['make' => 'AUDI', 'page' => 1],
     * ]
     *
     * @return int|PDFlib
     */
    public function vehicle1Guide(PDFlib $oCatalog, array $aValue, bool $sBuffer = false)
    {
        $aPoint = array_merge($this->aOption['point'], [
            'x2' => 562,
            'cellWidth' => 262 , // 表格宽度
            'cellWidth1' => 172, // 表格1宽度
            'cellWidth2' => 90, // 表格2宽度
            'cellHeight' => 10, // 表格高度
        ]);
        
        $sRemark = $aValue['remark'] ?? '';
        $aValue = $aValue['value'];
        
        // 绘制表格
        $sBook = 0;
        $sSkip = ceil(count($aValue) / (75 * 2));
        for ($sPage = 1; $sPage <= $sSkip; $sPage ++)
        {
            $sResult = 0;
            $oCatalog->begin_page_ext(0, 0, 'width=a4.width height=a4.height');
            
            if (!$sBook && $sRemark) {
                $oCatalog->create_bookmark($sRemark, sprintf('parent=%d', 0)); $sBook = 1;
            }
            
            for ($sLine = 1; $sLine <= 2; $sLine ++)
            {
                // 头部加粗
                $sCell = 0;
                $sOption = 'colwidth=%s rowheight=20 fittextline={font=%s fontsize=9 fitmethod=auto fillcolor=%s}';
                $sOption = sprintf($sOption, $aPoint['cellWidth1'], $this->aOption['font']['arial_bd'], $this->aOption['colors']['font']);
                $sCell = $oCatalog->addTableCell($sCell, 1, 1, 'MAKE-MODEL', $sOption);
                
                $sOption = 'colwidth=%s rowheight=20 fittextline={font=%s fontsize=9 fitmethod=auto fillcolor=%s}';
                $sOption = sprintf($sOption, $aPoint['cellWidth2'], $this->aOption['font']['arial_bd'], $this->aOption['colors']['font']);
                $sCell = $oCatalog->addTableCell($sCell, 2, 1, 'PAGE', $sOption);
                
                $sOption = sprintf('header=0 rowheightdefault=auto stroke={{line=other linewidth=1 strokecolor=%s}}', $this->aOption['colors']['line']);
                $oCatalog->fit_table(
                    $sCell,
                    $aPoint['x1']  + ($sLine - 1) * $aPoint['cellWidth'],
                    $aPoint['y2'] - 20,
                    $aPoint['x1'] + $sLine * $aPoint['cellWidth'],
                    $aPoint['y2'],
                    $sOption
                );
                
                // 填充单元格
                $sCell = 0;
                for ($sRow = 1; $sRow <= 75; $sRow ++)
                {
                    $aData = $aValue ? array_shift($aValue) : [1 => '', ''];
                    for ($sCol = 1; $sCol <= 2; $sCol ++)
                    {
                        $sData = ($sCol === 1) ? 'make' : 'page111';
                        $sOption = 'colwidth=%s rowheight=%d fittextline={font=%s fontsize=10 fitmethod=auto position=left} marginleft=3';
                        $sOption = sprintf($sOption, $aPoint['cellWidth'. $sCol], $aPoint['cellHeight'], $this->aOption['font']['arial']);
                        $sCell = $oCatalog->addTableCell($sCell, $sCol, $sRow, $aData[$sData], $sOption);
                    }
                }
                
                $sOption = sprintf('header=0 rowheightdefault=auto stroke={{line=vert1 linewidth=1 strokecolor=%s}}', $this->aOption['colors']['line']);
                $oCatalog->fit_table(
                    $sCell,
                    $aPoint['x1']  + ($sLine - 1) * $aPoint['cellWidth'],
                    $aPoint['y1'],
                    $aPoint['x1'] + $sLine * $aPoint['cellWidth'],
                    $aPoint['y2'] - 20,
                    $sOption
                );
                
                $sOption = 'colwidth=%s';
                $sOption = sprintf($sOption, $aPoint['cellWidth'], $this->aOption['font']['arial']);
                $sResult = $oCatalog->addTableCell($sResult, $sLine, 1, '', $sOption);
            }
            $sOption = sprintf('header=0 rowheightdefault=auto stroke={{line=other linewidth=1 strokecolor=%s}}', $this->aOption['colors']['line']);
            $oCatalog->fit_table($sResult, $aPoint['x1'], $aPoint['y1'], $aPoint['x2'], $aPoint['y2'], $sOption);
            $oCatalog = $this->pagination($oCatalog, $this->decToRoman($sPage));
            $oCatalog->end_page_ext('');
        }
        return $sBuffer ? ($sPage - 1) : $oCatalog;
    }
    
    /**
     * 说明页, 应用于将整张图片生成一页PDF
     *
     * @param PDFlib $oCatalog
     * @param array $aValue  数据
     *
     * @example [
     *      'value' => [
     *          dirname(__DIR__). '/image/header.jpg',
     *          dirname(__DIR__). '/image/header1.jpg',
     *          dirname(__DIR__). '/image/header2.jpg',
     *      ]
     * ]
     *
     * @return PDFlib
     */
    public function remarkGuide(PDFlib $oCatalog, array $aValue): PDFlib
    {
        if (isset($aValue['value']['imglist']) && $aValue['value']['imglist'])
        {
            foreach ($aValue['value']['imglist'] as $sValue)
            {
                $oCatalog->begin_page_ext(0, 0, 'width=a4.width height=a4.height');
                $oImage = $oCatalog->loadImage('auto', $sValue, '');
                if ($oImage < 1) {
                    dd($oCatalog->get_errmsg());
                }
                $oCatalog->fit_image($oImage, 0, 0, 'boxsize={595 842} fitmethod=meet showborder position=center');
                
                // 需要计算页码
                if ($aValue['value']['compute'])
                {
                    $this->aOption['pagination'] ++;
                    $oCatalog = $this->pagination($oCatalog, $this->aOption['pagination']);
                }
                $oCatalog->end_page_ext('');
            }
        }
        return $oCatalog;
    }
    
    /**
     * 轮毂参数页1(Hub Assemblies, BraKe Disc/Brake Drum)
     *
     * @param PDFlib $oCatalog
     * @param array $aValue  数据
     * @param false $sBuffer 是否只返回页码
     *
     *@example
     * [
     *      'style' => 'hubAssembliesByWheel | brakeByWheel', // 版式
     *      'title' => 'Hub Assemblies', // or BraKe Disc/Brake Drum 标题
     *      'value' => [
     *          // hubAssembliesByWheel (9列)
     *          ['col1' => $sRun + 1, 'col2' => '9228006K', 'col3' => $sRun, 'col4' => 97, 'col5'=> 'Ф10.5(4)', 'col6' => '56', 'col7' => '12', 'col8' => 28, 'col9' => '√'],
     *          ['col1' => $sRun + 1, 'col2' => '9228006K', 'col3' => $sRun, 'col4' => 97, 'col5'=> 'Ф10.5(4)', 'col6' => '56', 'col7' => '12', 'col8' => 28, 'col9' => '√'],
     *          ...
     *          // brakeByWheel (10列)
     *          ['col1' => $sRun + 1, 'col2' => '9228006K', 'col3' => $sRun, 'col4' => 97, 'col5'=> 'Ф10.5(4)', 'col6' => '56', 'col7' => '12', 'col8' => 28, 'col9' => '√', 'col10' => '√'],
     *          ['col1' => $sRun + 1, 'col2' => '9228006K', 'col3' => $sRun, 'col4' => 97, 'col5'=> 'Ф10.5(4)', 'col6' => '56', 'col7' => '12', 'col8' => 28, 'col9' => '√', 'col10' => '√'],
     *          ...
     *      ],
     * ]
     *
     * @return int|PDFlib
     */
    public function hubAssembliesByWheel(PDFlib $oCatalog, array $aValue, bool $sBuffer = false)
    {
        $aPoint = [
            'headerY1' => 788, // 标题头 高度
            'headerY2' => 765, // 子标题 高度
            
            'cellWidth' => $this->aOption['point']['x2'] - $this->aOption['point']['x1'], // 内容区域宽度
            'cellWidth1' => 24, // 第一列的宽度
            'cellWidth2' => 81, // 第二列的宽度
            'cellWidthOther' => 60, // 后面几列的宽度
            'cellHeight' => 11, // 表格高度
        ];
        
        // 介绍图
        $aPoint['table1'] = [
            // 左下点
            'x1' => $this->aOption['point']['x1'],
            'y1' => $aPoint['headerY2'] - 129,
            // 右上点
            'x2' => $this->aOption['point']['x2'],
            'y2' => $aPoint['headerY2'],
        ];
        
        // 内容格
        $aPoint['table2'] = [
            'x1' => $this->aOption['point']['x1'],
            'y1' => $this->aOption['point']['y1'],
            'x2' => $this->aOption['point']['x2'],
            'y2' => $aPoint['table1']['y1']
        ];
        
        $sTake = 51;
        $sTitle = $aValue['title'];
        $sRemark = $aValue['remark'] ?? '';
        $sStyle = $aValue['style'];
        $aValue = $aValue['value'];
        
        $sData = 0;
        $sSkip = ceil(count($aValue) / $sTake);
        for ($sPage = 1; $sPage <= $sSkip; $sPage ++)
        {
            // 新建页面
            $oCatalog->begin_page_ext(0, 0, 'width=a4.width height=a4.height');
            
            // 创建本分类区域书签
            if (!$sData && $sRemark) {
                $oCatalog->create_bookmark($sRemark, sprintf('parent=%d', 0)); $sData = 1;
            }
            
            // 标题头
            $sOption = sprintf('fontname={font/arial_bd} embedding fontsize=24 encoding=unicode fillcolor=%s', $this->aOption['colors']['font']);
            $oCatalog->fit_textline($sTitle, $this->aOption['point']['x1'], $aPoint['headerY1'], $sOption);
            
            // 子标题
            $sOption = sprintf('fontname={font/arial} embedding fontsize=14 encoding=unicode fillcolor=%s', $this->aOption['colors']['font']);
            $oCatalog->fit_textline(sprintf('Basic Dimension Table %s to Dimension………………………………………………', $this->aOption['ver']), $this->aOption['point']['x1'], $aPoint['headerY2'] + 5, $sOption);
            
            // 中间介绍图, 图片介绍, 使用表格居中
            $sResult = 0;
            if ($sStyle == 'brakeByWheel')
            {
                $oImage = $oCatalog->loadImage('auto', $this->aOption['image']['brake'], '');
                $sOption = sprintf('image=%s fitimage={position={center}}', $oImage);
                $sResult = $oCatalog->addTableCell($sResult, 1, 1, '', $sOption);
            } else
            {
                for ($sRun = 1; $sRun < 3; $sRun ++)
                {
                    $oImage = $oCatalog->loadImage('auto', $this->aOption['image'][sprintf('hubAssemblies%d', $sRun)], '');
                    $sOption = sprintf('colwidth=50%% image=%s fitimage={position={center}}', $oImage);
                    $sResult = $oCatalog->addTableCell($sResult, $sRun, 1, '', $sOption);
                }
            }
            
            // 画表格
            $sOption = 'header=0 rowheightdefault=auto';
            $oCatalog->fit_table($sResult, $aPoint['table1']['x1'], $aPoint['table1']['y1'], $aPoint['table1']['x2'], $aPoint['table1']['y2'], $sOption);
            
            // 内容
            $sCell = 0;
            $aCell = [
                1 => [1 => [1, 2, 2, 'ID'], 2 => [1, 2, 2, $this->aOption['gTitle']], 3 => [5, 1, 2, 'BASIC DIMENSIONS(mm)'], 8 => [1, 2, 1, 'TEETH / d'], 9 => [1, 2, 1, 'ABS']],
                2 => [3 => [1, 1, 1, 'A'], 4 => [1, 1, 1, 'B'], 5 => [1, 1, 1, 'C'], 6 => [1, 1, 1, 'D'], 7 => [1, 1, 1, 'F']],
            ];
            $sResult = 0;
            foreach ($aCell as $sRow =>$aItem)
            {
                foreach ($aItem as $sCol => $aData)
                {
                    switch ($sCol)
                    {
                        case 1:
                        case 2: $sWidth = $aPoint[sprintf('cellWidth%d', $sCol)]; break;
                        default: $sWidth = $aPoint['cellWidthOther']; break;
                    }
                    if (($sRow == 1) && ($sCol == 3)) {
                        $sWidth = $sWidth * 5;
                    }

                    $sOption = 'colwidth=%s rowheight=%s fittextline={font=%s fontsize=9 fillcolor=%s fitmethod=auto position={center}} colspan=%d rowspan=%d';
                    $sOption = sprintf($sOption, $sWidth, $aPoint['cellHeight'] * $aData[2], $this->aOption['font']['arial_bd'], $this->aOption['colors']['font'], $aData[0], $aData[1]);
                    $sCell = $oCatalog->addTableCell($sCell, $sCol, $sRow, $aData[3], $sOption);
                }
            }

            $sOption = 'header=0 rowheightdefault=auto stroke={{line=other linewidth=1 strokecolor=%s}} fill={{area=table fillcolor=%s}}';
            $sOption = sprintf($sOption, $this->aOption['colors']['line'], $this->aOption['colors']['back']);
            $oCatalog->fit_table($sCell, $aPoint['table2']['x1'], $aPoint['table2']['y1'] - $aPoint['cellHeight'] * 2, $aPoint['table2']['x2'], $aPoint['table2']['y2'], $sOption);
            
            // 内容填充单元格
            for ($sRow = 1; $sRow <= 51; $sRow ++)
            {
                if (!$aValue) {
                    continue;
                }
                
                $aShift = array_shift($aValue);
                for ($sCol = 1; $sCol <= 9; $sCol ++)
                {
                    switch ($sCol)
                    {
                        case 1:
                        case 2: $sWidth = $aPoint[sprintf('cellWidth%d', $sCol)]; break;
                        default: $sWidth = $aPoint['cellWidthOther']; break;
                    }
                    $sOption = 'colwidth=%s rowheight=%s fittextline={font=%s fontsize=7 fitmethod=auto position={center}}';
                    $sOption = sprintf($sOption, $sWidth, $aPoint['cellHeight'], $this->aOption['font'][($sCol == 2) ? 'arial_bd' : 'arial']);
                    $sResult = $oCatalog->addTableCell($sResult, $sCol, $sRow, $aShift[sprintf('col%d', $sCol)] ?? '', $sOption);
                }
            }
            $sOption = 'header=0 rowheightdefault=auto stroke={{line=frame linewidth=1 strokecolor=%s} {line=other linewidth=0.1}} fill={{area=roweven fillcolor=%s}}';
            $sOption = sprintf($sOption, $this->aOption['colors']['line'], $this->aOption['colors']['back']);
            $oCatalog->fit_table($sResult, $aPoint['table2']['x1'], $aPoint['table2']['y1'], $aPoint['table2']['x2'], $aPoint['table2']['y2'] - $aPoint['cellHeight'] * 2, $sOption);
            
            $oCatalog = $this->pagination($oCatalog, $this->aOption['pagination']);
            $oCatalog->end_page_ext('');
            $this->aOption['pagination'] ++;
        }
        
        return $sBuffer ? ($this->aOption['pagination'] - 1) : $oCatalog;
    }
    
    /**
     * 轮毂参数页3(Drive Shaft)
     *
     * @param PDFlib $oCatalog
     * @param array $aValue  数据
     * @param false $sBuffer 是否只返回页码
     *
     *@example
     * [
     *      'style' => 'driveShaftByWheel', // 版式
     *      'title' => 'Drive Shaft', // 标题
     *      'value' => [
     *          ['col1' => $sRun + 1, 'col2' => '9228006K', 'col3' => $sRun, 'col4' => 97, 'col5'=> 'Ф10.5(4)', 'col6' => '56', 'col7' => '12', 'col8' => 28, 'col9' => '√'],
     *          ['col1' => $sRun + 1, 'col2' => '9228006K', 'col3' => $sRun, 'col4' => 97, 'col5'=> 'Ф10.5(4)', 'col6' => '56', 'col7' => '12', 'col8' => 28, 'col9' => '√'],
     *          ...
     *      ]
     * ]
     *
     * @return int|PDFlib
     */
    public function driveShaftByWheel(PDFlib $oCatalog, array $aValue, bool $sBuffer = false)
    {
        $aPoint = [
            'headerY1' => 788,
            'headerY2' => 765,
            
            'cellWidth' => $this->aOption['point']['x2'] - $this->aOption['point']['x1'],
            'cellWidth1' => 24,
            'cellWidth2' => 81,
            'cellHeight' => 11, // 表格高度
        ];
        $aPoint['cellWidthOther'] = ($aPoint['cellWidth'] - $aPoint['cellWidth1'] - $aPoint['cellWidth2']) / 6;
        
        $aPoint['table1'] = [
            'x1' => $this->aOption['point']['x1'],
            'y1' => $aPoint['headerY2'] - 129,
            'x2' => $this->aOption['point']['x2'],
            'y2' => $aPoint['headerY2'],
        ];
        
        $aPoint['table2'] = [
            'x1' => $this->aOption['point']['x1'],
            'y1' => $this->aOption['point']['y1'],
            'x2' => $this->aOption['point']['x2'],
            'y2' => $aPoint['table1']['y1']
        ];
        
        $sData = 0;
        $sTake = 51;
        $sTitle = $aValue['title'];
        $sRemark = $aValue['remark'] ?? '';
        $aValue = $aValue['value'];
        
        $sSkip = ceil(count($aValue) / $sTake);
        for ($sPage = 1; $sPage <= $sSkip; $sPage ++)
        {
            $oCatalog->begin_page_ext(0, 0, 'width=a4.width height=a4.height');
            if (!$sData && $sRemark) {
                $oCatalog->create_bookmark($sRemark, sprintf('parent=%d', 0)); $sData = 1;
            }
            
            $sOption = 'fontname={font/arial_bd} embedding fontsize=24 encoding=unicode fillcolor=%s';
            $sOption = sprintf($sOption, $this->aOption['colors']['font']);
            $oCatalog->fit_textline($sTitle, $this->aOption['point']['x1'], $aPoint['headerY1'], $sOption);
            
            $sOption = 'fontname={font/arial} embedding fontsize=14 encoding=unicode fillcolor=%s';
            $sOption = sprintf($sOption, $this->aOption['colors']['font']);
            $oCatalog->fit_textline(sprintf('Basic Dimension Table %s to Dimension………………………………………………', $this->aOption['ver']), $this->aOption['point']['x1'], $aPoint['headerY2'] + 5, $sOption);
            
            $sResult = 0;
            $oImage = $oCatalog->loadImage('auto', $this->aOption['image']['driveShaft'], '');
            $sOption = sprintf('image=%s fitimage={position={center}}', $oImage);
            $sResult = $oCatalog->addTableCell($sResult, 1, 1, '', $sOption);
            
            $sOption = 'header=0 rowheightdefault=auto';
            $oCatalog->fit_table($sResult, $aPoint['table1']['x1'], $aPoint['table1']['y1'], $aPoint['table1']['x2'], $aPoint['table1']['y2'], $sOption);
            
            // 内容
            // 解决头部粗线问题
            $sCell = 0;
            $aCell = [
                1 => [1 => [1, 2, 2, 'ID'], 2 => [1, 2, 2, $this->aOption['gTitle']], 3 => [6, 1, 2, 'BASIC DIMENSIONS(mm)'], 9 => [1, 2, 1, 'TEETH'], 10 => [1, 2, 1, 'ABS']],
                2 => [3 => [1, 1, 1, 'A'], 4 => [1, 1, 1, 'B'], 5 => [1, 1, 1, 'C'], 6 => [1, 1, 1, 'D'], 7 => [1, 1, 1, 'F'], 8 => [1, 1, 1, 'L']],
            ];
            foreach ($aCell as $sRow => $aItem)
            {
                foreach ($aItem as $sCol => $aData)
                {
                    switch ($sCol)
                    {
                        case 1:
                        case 2: $sWidth = $aPoint[sprintf('cellWidth%d', $sCol)]; break;
                        default: $sWidth = $aPoint['cellWidthOther']; break;
                    }
                    if (($sRow == 1) && ($sCol == 3)) {
                        $sWidth = $sWidth * 6;
                    }
                    
                    $sOption = 'colwidth=%s rowheight=%s fittextline={font=%s fontsize=9 fillcolor=%s fitmethod=auto position={center}} colspan=%d rowspan=%d';
                    $sOption = sprintf($sOption, $sWidth, $aPoint['cellHeight'] * $aData[2], $this->aOption['font']['arial_bd'], $this->aOption['colors']['font'], $aData[0], $aData[1]);
                    $sCell = $oCatalog->addTableCell($sCell, $sCol, $sRow, $aData[3], $sOption);
                }
            }
            $sOption = 'header=0 rowheightdefault=auto stroke={{line=other linewidth=1 strokecolor=%s}} fill={{area=table fillcolor=%s}}';
            $sOption = sprintf($sOption, $this->aOption['colors']['line'], $this->aOption['colors']['back']);
            $oCatalog->fit_table($sCell, $aPoint['table2']['x1'], $aPoint['table2']['y1'] - $aPoint['cellHeight'] * 2, $aPoint['table2']['x2'], $aPoint['table2']['y2'], $sOption);
            
            // 填充单元格
            $sResult = 0;
            for ($sRow = 1; $sRow <= 51; $sRow ++)
            {
                if (!$aValue) {
                    continue;
                }
                
                $aShift = array_shift($aValue);
                for ($sCol = 1; $sCol <= 10; $sCol ++)
                {
                    switch ($sCol)
                    {
                        case 1:
                        case 2: $sWidth = $aPoint[sprintf('cellWidth%d', $sCol)]; break;
                        default: $sWidth = $aPoint['cellWidthOther']; break;
                    }
                    $sOption = 'colwidth=%s rowheight=%s fittextline={font=%s fontsize=7 fitmethod=auto position={center}}';
                    $sOption = sprintf($sOption, $sWidth, $aPoint['cellHeight'], $this->aOption['font'][($sCol == 2) ? 'arial_bd' : 'arial']);
                    $sResult = $oCatalog->addTableCell($sResult, $sCol, $sRow, $aShift[sprintf('col%d', $sCol)] ?? '', $sOption);
                }
            }
            $sOption = 'header=0 rowheightdefault=auto stroke={{line=frame linewidth=1 strokecolor=%s} {line=other linewidth=0.1}} fill={{area=roweven fillcolor=%s}}';
            $sOption = sprintf($sOption, $this->aOption['colors']['line'], $this->aOption['colors']['back']);
            $oCatalog->fit_table($sResult, $aPoint['table2']['x1'], $aPoint['table2']['y1'], $aPoint['table2']['x2'], $aPoint['table2']['y2'] - $aPoint['cellHeight'] * 2, $sOption);
            
            $oCatalog = $this->pagination($oCatalog, $this->aOption['pagination']);
            $oCatalog->end_page_ext('');
            $this->aOption['pagination'] ++;
        }
        
        return $sBuffer ? ($this->aOption['pagination'] - 1) : $oCatalog;
    }

    /**
     * 轮毂参数模板2(Bearing Kits) 一行一列
     *
     * @param PDFlib $oCatalog
     * @param array $aValue  数据
     * @param false $sBuffer 是否只返回页码
     *
     *
     * 2022-08-05 修改了版式,  传递过来的数据没有改变 请使用@function bearingKitsByWheelOld 数据格式
     *
     * 这里是新的数据格式， 如果要使用新的数据格式， 请修改代码中 @2022-08-05 异常部分
     * @example
     * [
     *      'style' => 'bearingKitsByWheel', // 版式
     *      'title' => 'Bearing Kits', // 标题
     *      'value' => [
     *          ['col1' => 1, 'col2' => 'GK6537', 'col3' => 'Ф10.5(4)', 'col4' => '56', 'col5' => 23, 'col6' => 23, 'col7' => 23],
    *           ['col1' => 1, 'col2' => 'GK6537', 'col3' => 'Ф10.5(4)', 'col4' => '56', 'col5' => 23, 'col6' => 23, 'col7' => 23],
    *           ...
     *      ]
     * ]
     *
     * @return int|PDFlib
     */
    public function bearingKitsByWheel(PDFlib $oCatalog, array $aValue, bool $sBuffer = false)
    {
        $aPoint = array_merge($this->aOption['point'], [
            'headerY1' => 788,
            'headerY2' => 765,

            'cellWidth' => $this->aOption['point']['x2'] - $this->aOption['point']['x1'],
            'cellWidth1' => 24,
            'cellWidth2' => 81,
            'cellWidthOther' => 90,
            'cellWidth6' => 70,
            'cellWidth7' => 80,
            'cellHeight' => 11, // 表格高度
        ]);

        $aPoint['table1'] = [
            'x1' => $this->aOption['point']['x1'],
            'y1' => $aPoint['headerY2'] - 129,
            'x2' => $this->aOption['point']['x2'],
            'y2' => $aPoint['headerY2'],
        ];

        $aPoint['table2'] = [
            'x1' => $this->aOption['point']['x1'],
            'y1' => $this->aOption['point']['y1'],
            'x2' => $this->aOption['point']['x2'],
            'y2' => $aPoint['table1']['y1']
        ];

        // 内容页面
        $sData = 0;
        $sTake = 51;
        $sTitle = $aValue['title'];
        $sRemark = $aValue['remark'] ?? '';
        $aBuild = $aValue['value'];

        /**
         * 2022-08-05 修改了版式,  传递过来的数据没有改变
         */
        $aValue = [];
        foreach ($aBuild as $aVVV)
        {
            foreach ($aVVV['value'] as $aVV1)
            {
                $aData = [];
                foreach ($aVV1 as $sKK2 => $sVV2)
                {
                    $sVV3 = substr($sKK2, -1) + 2;
                    $aData[sprintf('col%d', $sVV3)] = $sVV2;
                }

                $aValue[] = array_merge($aData, [
                    'col1' => $aVVV['stream'],
                    'col2' => $aVVV['product'],
                ]);
            }
        }

        $sCount = count($aValue);
        $sSkip = ceil($sCount / $sTake);
        for ($sPage = 1; $sPage <= $sSkip; $sPage ++)
        {
            $oCatalog->begin_page_ext(0, 0, 'width=a4.width height=a4.height');
            if (!$sData && $sRemark) {
                $oCatalog->create_bookmark($sRemark, sprintf('parent=%d', 0)); $sData = 1;
            }

            // 页头设置
            $sOption = 'fontname={font/arial_bd} embedding fontsize=24 encoding=unicode fillcolor=%s';
            $sOption = sprintf($sOption, $this->aOption['colors']['font']);
            $oCatalog->fit_textline($sTitle, $this->aOption['point']['x1'], $aPoint['headerY1'], $sOption);

            $sOption = 'fontname={font/arial} embedding fontsize=14 encoding=unicode fillcolor=%s';
            $sOption = sprintf($sOption, $this->aOption['colors']['font']);
            $oCatalog->fit_textline(sprintf('Basic Dimension Table %s to Dimension………………………………………………', $this->aOption['ver']), $this->aOption['point']['x1'], $aPoint['headerY2'], $sOption);

            $sResult = 0;
            $oImage = $oCatalog->loadImage('auto', $this->aOption['image']['bearingKits1'], '');
            $sOption = sprintf('colwidth=50%% image=%s fitimage={position={right center}} margin=5', $oImage);
            $sResult = $oCatalog->addTableCell($sResult, 1, 1, '', $sOption);

            $oImage = $oCatalog->loadImage('auto', $this->aOption['image']['bearingKits2'], '');
            $sOption = sprintf('colwidth=50%% image=%s fitimage={position={left center}} margin=5', $oImage);
            $sResult = $oCatalog->addTableCell($sResult, 2, 1, '', $sOption);

            $sOption = 'header=0 rowheightdefault=auto';
            $oCatalog->fit_table($sResult, $aPoint['table1']['x1'], $aPoint['table1']['y1'], $aPoint['table1']['x2'], $aPoint['table1']['y2'], $sOption);

            // 内容
            // 解决头部粗线问题
            $sCell = 0;
            $aCell = [
                1 => [1 => [1, 2, 2, 'ID'], 2 => [1, 2, 2, $this->aOption['gTitle']], 3 => [4, 1, 2, 'BASIC DIMENSIONS(mm)'], 7 => [1, 2, 1, 'ABS']],
                2 => [3 => [1, 1, 1, 'd'], 4 => [1, 1, 1, 'D'], 5 => [1, 1, 1, 'B'], 6 => [1, 1, 1, 'C']],
            ];
            foreach ($aCell as $sRow => $aItem)
            {
                foreach ($aItem as $sCol => $aData)
                {
                    switch ($sCol)
                    {
                        case 1:
                        case 2:
                        case 6:
                        case 7: $sWidth = $aPoint[sprintf('cellWidth%d', $sCol)]; break;
                        default: $sWidth = $aPoint['cellWidthOther']; break;
                    }
                    if (($sRow == 1) && ($sCol == 3)) {
                        $sWidth = $sWidth * 3;
                    }

                    $sOption = 'colwidth=%s rowheight=%s fittextline={font=%s fontsize=9 fitmethod=auto fillcolor=%s position={center}} colspan=%d rowspan=%d';
                    $sOption = sprintf($sOption, $sWidth, $aPoint['cellHeight'] * $aData[2], $this->aOption['font']['arial_bd'], $this->aOption['colors']['font'], $aData[0], $aData[1]);
                    $sCell = $oCatalog->addTableCell($sCell, $sCol, $sRow, $aData[3], $sOption);
                }
            }
            $sOption = 'header=0 rowheightdefault=auto stroke={{line=other linewidth=1 strokecolor=%s}} fill={{area=table fillcolor=%s}}';
            $sOption = sprintf($sOption, $this->aOption['colors']['line'], $this->aOption['colors']['back']);
            $oCatalog->fit_table($sCell, $aPoint['table2']['x1'], $aPoint['table2']['y1'] - $aPoint['cellHeight'] * 2, $aPoint['table2']['x2'], $aPoint['table2']['y2'], $sOption);

            // 填充单元格
            $sResult = 0;
            for ($sRow = 1; $sRow <= 51; $sRow ++)
            {
                if (!$aValue) {
                    continue;
                }

                $aShift = array_shift($aValue);
                for ($sCol = 1; $sCol <= 7; $sCol ++)
                {
                    switch ($sCol)
                    {
                        case 2:
                        case 7:
                        case 6:
                        case 1: $sValue = $aShift[sprintf('col%d', $sCol)]; $sWidth = $aPoint[sprintf('cellWidth%d', $sCol)]; break;
                        case 3:
                        case 4:
                        case 5: $sValue = $aShift[sprintf('col%d', $sCol)]; $sWidth = $aPoint['cellWidthOther']; break;
                        default: $sValue = ''; $sWidth = 0; break;
                    }

                    $sRowspan = 1;
                    $sOption = 'colwidth=%s rowheight=%s fittextline={font=%s fontsize=7 fitmethod=auto position={center}} matchbox={fillcolor=%s} rowspan=%d';
                    $sOption = sprintf($sOption, $sWidth, $aPoint['cellHeight'], $this->aOption['font'][($sCol == 2) ? 'arial_bd' : 'arial'], (($sRow % 2) == 0) ? $this->aOption['colors']['back'] : $this->aOption['colors']['white'], $sRowspan);
                    $sResult = $oCatalog->addTableCell($sResult, $sCol, $sRow, $sValue, $sOption);
                }
            }

            $sOption = 'header=0 rowheightdefault=auto stroke={
                    {line=frame linewidth=1 strokecolor=%s} 
                    {line=vert1 linewidth=1 strokecolor=%s} 
                    {line=vert2 linewidth=1 strokecolor=%s} 
                    {line=other linewidth=0.1}
                }';
            $sOption = sprintf($sOption, $this->aOption['colors']['line'], $this->aOption['colors']['line'], $this->aOption['colors']['line']);
            $oCatalog->fit_table($sResult, $aPoint['table2']['x1'], $aPoint['table2']['y1'], $aPoint['table2']['x2'], $aPoint['table2']['y2'] - $aPoint['cellHeight'] * 2, $sOption);

            $oCatalog = $this->pagination($oCatalog, $this->aOption['pagination']);
            $oCatalog->end_page_ext('');
            $this->aOption['pagination'] ++;
        }

        return $sBuffer ? ($this->aOption['pagination'] - 1) : $oCatalog;
    }
    
    /**
     * 轮毂参数模板2(Bearing Kits)
     *
     * @param PDFlib $oCatalog
     * @param array $aValue  数据
     * @param false $sBuffer 是否只返回页码
     *
     * @example
     * [
     *      'style' => 'bearingKitsByWheel', // 版式
     *      'title' => 'Bearing Kits', // 标题
     *      'value' => [
     *          [
     *              'stream' => 1,
     *              'product' => 'GK6537',
     *              'value' => [
     *                  ['col1' => 1, 'col2' => 97, 'col3' => 'Ф10.5(4)', 'col4' => '56', 'col5' => 23],
     *                  ['col1' => 1, 'col2' => 97, 'col3' => 'Ф10.5(4)', 'col4' => '56', 'col5' => 23],
     *                  ...
     *              ]
     *          ],
     *          [
     *              'stream' => 2,
     *              'product' => 'GK6538',
     *              'value' => [
     *                  ['col1' => 1, 'col2' => 97, 'col3' => 'Ф10.5(4)', 'col4' => '56', 'col5' => 23],
     *                  ['col1' => 2, 'col2' => 97, 'col3' => 'Ф10.5(4)', 'col4' => '56', 'col5' => 23],
     *              ]
     *          ]
     *      ]
     * ]
     *
     * @return int|PDFlib
     */
    public function bearingKitsByWheelOld(PDFlib $oCatalog, array $aValue, bool $sBuffer = false)
    {
        $aPoint = array_merge($this->aOption['point'], [
            'headerY1' => 788,
            'headerY2' => 765,
            
            'cellWidth' => $this->aOption['point']['x2'] - $this->aOption['point']['x1'],
            'cellWidth1' => 24,
            'cellWidth2' => 81,
            'cellWidthOther' => 90,
            'cellWidth6' => 70,
            'cellWidth7' => 80,
            'cellHeight' => 11, // 表格高度
        ]);
        
        $aPoint['table1'] = [
            'x1' => $this->aOption['point']['x1'],
            'y1' => $aPoint['headerY2'] - 129,
            'x2' => $this->aOption['point']['x2'],
            'y2' => $aPoint['headerY2'],
        ];
        
        $aPoint['table2'] = [
            'x1' => $this->aOption['point']['x1'],
            'y1' => $this->aOption['point']['y1'],
            'x2' => $this->aOption['point']['x2'],
            'y2' => $aPoint['table1']['y1']
        ];
        
        // 内容页面
        $sData = 0;
        $sTake = 51;
        $sCount = 0;
        $sTitle = $aValue['title'];
        $sRemark = $aValue['remark'] ?? '';
        $aValue = $aValue['value'];
        foreach ($aValue as $aItem) {
            $sCount = $sCount + count($aItem['value']);
        }
        $sSkip = ceil($sCount / $sTake);
        for ($sPage = 1; $sPage <= $sSkip; $sPage ++)
        {
            $oCatalog->begin_page_ext(0, 0, 'width=a4.width height=a4.height');
            if (!$sData && $sRemark) {
                $oCatalog->create_bookmark($sRemark, sprintf('parent=%d', 0)); $sData = 1;
            }
            
            // 页头设置
            $sOption = 'fontname={font/arial_bd} embedding fontsize=24 encoding=unicode fillcolor=%s';
            $sOption = sprintf($sOption, $this->aOption['colors']['font']);
            $oCatalog->fit_textline($sTitle, $this->aOption['point']['x1'], $aPoint['headerY1'], $sOption);
            
            $sOption = 'fontname={font/arial} embedding fontsize=14 encoding=unicode fillcolor=%s';
            $sOption = sprintf($sOption, $this->aOption['colors']['font']);
            $oCatalog->fit_textline(sprintf('Basic Dimension Table %s to Dimension………………………………………………', $this->aOption['ver']), $this->aOption['point']['x1'], $aPoint['headerY2'], $sOption);
            
            $sResult = 0;
            $oImage = $oCatalog->loadImage('auto', $this->aOption['image']['bearingKits1'], '');
            $sOption = sprintf('colwidth=50%% image=%s fitimage={position={right center}} margin=5', $oImage);
            $sResult = $oCatalog->addTableCell($sResult, 1, 1, '', $sOption);
            
            $oImage = $oCatalog->loadImage('auto', $this->aOption['image']['bearingKits2'], '');
            $sOption = sprintf('colwidth=50%% image=%s fitimage={position={left center}} margin=5', $oImage);
            $sResult = $oCatalog->addTableCell($sResult, 2, 1, '', $sOption);
            
            $sOption = 'header=0 rowheightdefault=auto';
            $oCatalog->fit_table($sResult, $aPoint['table1']['x1'], $aPoint['table1']['y1'], $aPoint['table1']['x2'], $aPoint['table1']['y2'], $sOption);
            
            // 内容
            // 解决头部粗线问题
            $sCell = 0;
            $aCell = [
                1 => [1 => [1, 2, 2, 'ID'], 2 => [1, 2, 2, $this->aOption['gTitle']], 3 => [4, 1, 2, 'BASIC DIMENSIONS(mm)'], 7 => [1, 2, 1, 'ABS']],
                2 => [3 => [1, 1, 1, 'd'], 4 => [1, 1, 1, 'D'], 5 => [1, 1, 1, 'B'], 6 => [1, 1, 1, 'C']],
            ];
            foreach ($aCell as $sRow => $aItem)
            {
                foreach ($aItem as $sCol => $aData)
                {
                    switch ($sCol)
                    {
                        case 1:
                        case 2:
                        case 6:
                        case 7: $sWidth = $aPoint[sprintf('cellWidth%d', $sCol)]; break;
                        default: $sWidth = $aPoint['cellWidthOther']; break;
                    }
                    if (($sRow == 1) && ($sCol == 3)) {
                        $sWidth = $sWidth * 3;
                    }
                    
                    $sOption = 'colwidth=%s rowheight=%s fittextline={font=%s fontsize=9 fitmethod=auto fillcolor=%s position={center}} colspan=%d rowspan=%d';
                    $sOption = sprintf($sOption, $sWidth, $aPoint['cellHeight'] * $aData[2], $this->aOption['font']['arial_bd'], $this->aOption['colors']['font'], $aData[0], $aData[1]);
                    $sCell = $oCatalog->addTableCell($sCell, $sCol, $sRow, $aData[3], $sOption);
                }
            }
            $sOption = 'header=0 rowheightdefault=auto stroke={{line=other linewidth=1 strokecolor=%s}} fill={{area=table fillcolor=%s}}';
            $sOption = sprintf($sOption, $this->aOption['colors']['line'], $this->aOption['colors']['back']);
            $oCatalog->fit_table($sCell, $aPoint['table2']['x1'], $aPoint['table2']['y1'] - $aPoint['cellHeight'] * 2, $aPoint['table2']['x2'], $aPoint['table2']['y2'], $sOption);
            
            // 填充单元格
            $aShift = [];
            $sShift = 1;
            $sFirst = true;
            $sResult = 0;
            for ($sRow = 1; $sRow <= 51; $sRow ++)
            {
                if (!$aValue && !$aShift['value']) {
                    continue;
                }
                
                if (!isset($aShift['value']) || !$aShift['value'])
                {
                    $sFirst = true;
                    $aShift = array_shift($aValue);
                    $sShift = count($aShift['value']);
                    // 计算剩余行数
                    $sShift = (($sShift + $sRow) > 51) ? (51 - $sRow) + 1 : $sShift;
                }
                
                $aData = array_shift($aShift['value']);
                for ($sCol = 1; $sCol <= 7; $sCol ++)
                {
                    if (!$sFirst && ($sCol < 3)) {
                        continue;
                    }
                    
                    switch ($sCol)
                    {
                        case 1: $sValue = $aShift['stream']; $sWidth = $aPoint[sprintf('cellWidth%d', $sCol)]; break;
                        case 2: $sValue = $aShift['product']; $sWidth = $aPoint[sprintf('cellWidth%d', $sCol)]; break;
                        case 3:
                        case 4:
                        case 5: $sValue = $aData[sprintf('col%d', $sCol - 2)]; $sWidth = $aPoint['cellWidthOther']; break;
                        case 6:
                        case 7: $sValue = $aData[sprintf('col%d', $sCol - 2)]; $sWidth = $aPoint[sprintf('cellWidth%d', $sCol)]; break;
                        default: $sValue = ''; $sWidth = 0; break;
                    }
                    
                    $sRowspan = 1;
                    if ($sFirst && ($sCol < 3)) {
                        $sRowspan = $sShift;
                    }
                    
                    $sOption = 'colwidth=%s rowheight=%s fittextline={font=%s fontsize=7 fitmethod=auto position={center}} matchbox={fillcolor=%s} rowspan=%d';
                    $sOption = sprintf($sOption, $sWidth, $aPoint['cellHeight'], $this->aOption['font'][($sCol == 2) ? 'arial_bd' : 'arial'], ($sCol == 2) ? $this->aOption['colors']['back'] : $this->aOption['colors']['white'], $sRowspan);
                    $sResult = $oCatalog->addTableCell($sResult, $sCol, $sRow, $sValue, $sOption);
                }
                
                $sFirst = false;
            }
            
            if ($aShift['value']) {
                array_unshift($aValue, $aShift);
            }
            
            $sOption = 'header=0 rowheightdefault=auto stroke={
                    {line=frame linewidth=1 strokecolor=%s} 
                    {line=vert1 linewidth=1 strokecolor=%s} 
                    {line=vert2 linewidth=1 strokecolor=%s} 
                    {line=other linewidth=0.1}
                }';
            $sOption = sprintf($sOption, $this->aOption['colors']['line'], $this->aOption['colors']['line'], $this->aOption['colors']['line']);
            $oCatalog->fit_table($sResult, $aPoint['table2']['x1'], $aPoint['table2']['y1'], $aPoint['table2']['x2'], $aPoint['table2']['y2'] - $aPoint['cellHeight'] * 2, $sOption);
            
            $oCatalog = $this->pagination($oCatalog, $this->aOption['pagination']);
            $oCatalog->end_page_ext('');
            $this->aOption['pagination'] ++;
        }
        
        return $sBuffer ? ($this->aOption['pagination'] - 1) : $oCatalog;
    }

    /**
     * 轮毂参数模板(Stub Axle)
     *
     * @param PDFlib $oCatalog
     * @param array $aValue  数据
     * @param false $sBuffer 是否只返回页码
     *
     * @example
     * [
     *      'style' => 'stubAxleByWheel', // 版式
     *      'title' => 'Stub Axle', // 标题
     *      'value' => [
     *          ['col1' => $sRun + 1, 'col2' => '9228006K', 'col3' => $sRun, 'col4' => 97, 'col5'=> 'Ф10.5(4)', 'col6' => '56', 'col7' => '12', 'col8' => 28, 'col9' => '√', 'col10' => '√'],
     *          ...
     *      ]
     *
     * @return int|PDFlib
     */
    public function stubAxleByWheel(PDFlib $oCatalog, array $aValue, bool $sBuffer = false)
    {
        $aPoint = [
            'headerY1' => 788,
            'headerY2' => 765,

            'cellWidth' => $this->aOption['point']['x2'] - $this->aOption['point']['x1'],
            'cellWidth1' => 24,
            'cellWidth2' => 81,
            'cellHeight' => 11, // 表格高度
        ];
        $aPoint['cellWidthOther'] = ($aPoint['cellWidth'] - $aPoint['cellWidth1'] - $aPoint['cellWidth2']) / 6;

        $aPoint['table1'] = [
            'x1' => $this->aOption['point']['x1'],
            'y1' => $aPoint['headerY2'] - 129,
            'x2' => $this->aOption['point']['x2'],
            'y2' => $aPoint['headerY2'],
        ];

        $aPoint['table2'] = [
            'x1' => $this->aOption['point']['x1'],
            'y1' => $this->aOption['point']['y1'],
            'x2' => $this->aOption['point']['x2'],
            'y2' => $aPoint['table1']['y1']
        ];

        $sData = 0;
        $sTake = 51;
        $sTitle = $aValue['title'];
        $sRemark = $aValue['remark'] ?? '';
        $aValue = $aValue['value'];

        $sSkip = ceil(count($aValue) / $sTake);
        for ($sPage = 1; $sPage <= $sSkip; $sPage ++)
        {
            $oCatalog->begin_page_ext(0, 0, 'width=a4.width height=a4.height');
            if (!$sData && $sRemark) {
                $oCatalog->create_bookmark($sRemark, sprintf('parent=%d', 0)); $sData = 1;
            }

            $sOption = 'fontname={font/arial_bd} embedding fontsize=24 encoding=unicode fillcolor=%s';
            $sOption = sprintf($sOption, $this->aOption['colors']['font']);
            $oCatalog->fit_textline($sTitle, $this->aOption['point']['x1'], $aPoint['headerY1'], $sOption);

            $sOption = 'fontname={font/arial} embedding fontsize=14 encoding=unicode fillcolor=%s';
            $sOption = sprintf($sOption, $this->aOption['colors']['font']);
            $oCatalog->fit_textline(sprintf('Basic Dimension Table %s to Dimension………………………………………………', $this->aOption['ver']), $this->aOption['point']['x1'], $aPoint['headerY2'] + 5, $sOption);

            $sResult = 0;
            $oImage = $oCatalog->loadImage('auto', $this->aOption['image']['stubAxle1'], '');
            $sOption = sprintf('colwidth=50%% image=%s fitimage={position={center}} margin=5', $oImage);
            $sResult = $oCatalog->addTableCell($sResult, 1, 1, '', $sOption);

            $oImage = $oCatalog->loadImage('auto', $this->aOption['image']['stubAxle2'], '');
            $sOption = sprintf('colwidth=50%% image=%s fitimage={position={center}} margin=5', $oImage);
            $sResult = $oCatalog->addTableCell($sResult, 2, 1, '', $sOption);

            $sOption = 'header=0 rowheightdefault=auto';
            $oCatalog->fit_table($sResult, $aPoint['table1']['x1'], $aPoint['table1']['y1'], $aPoint['table1']['x2'], $aPoint['table1']['y2'], $sOption);

            // 内容
            // 解决头部粗线问题
            $sCell = 0;
            $aCell = [
                1 => [1 => [1, 2, 2, 'ID'], 2 => [1, 2, 2, $this->aOption['gTitle']], 3 => [7, 1, 2, 'BASIC DIMENSIONS(mm)'], 10 => [1, 2, 1, 'ABS']],
                2 => [3 => [1, 1, 1, 'D1'], 4 => [1, 1, 1, 'D2'], 5 => [1, 1, 1, 'F'], 6 => [1, 1, 1, 'H'], 7 => [1, 1, 1, 'I'], 8 => [1, 1, 1, 'L'], 9 => [1, 1, 1, 'M']],
            ];
            foreach ($aCell as $sRow =>$aItem)
            {
                foreach ($aItem as $sCol => $aData)
                {
                    switch ($sCol)
                    {
                        case 1:
                        case 2: $sWidth = $aPoint[sprintf('cellWidth%d', $sCol)]; break;
                        default: $sWidth = $aPoint['cellWidthOther']; break;
                    }
                    if (($sRow == 1) && ($sCol == 3)) {
                        $sWidth = $sWidth * 6;
                    }

                    $sOption = 'colwidth=%s rowheight=%s fittextline={font=%s fontsize=9 fillcolor=%s fitmethod=auto position={center}} colspan=%d rowspan=%d';
                    $sOption = sprintf($sOption, $sWidth, $aPoint['cellHeight'] * $aData[2], $this->aOption['font']['arial_bd'], $this->aOption['colors']['font'], $aData[0], $aData[1]);
                    $sCell = $oCatalog->addTableCell($sCell, $sCol, $sRow, $aData[3], $sOption);
                }
            }
            $sOption = 'header=0 rowheightdefault=auto stroke={{line=other linewidth=1 strokecolor=%s}} fill={{area=table fillcolor=%s}}';
            $sOption = sprintf($sOption, $this->aOption['colors']['line'], $this->aOption['colors']['back']);
            $oCatalog->fit_table($sCell, $aPoint['table2']['x1'], $aPoint['table2']['y1'] - $aPoint['cellHeight'] * 2, $aPoint['table2']['x2'], $aPoint['table2']['y2'], $sOption);

            // 填充单元格
            $sResult = 0;
            for ($sRow = 1; $sRow <= 51; $sRow ++)
            {
                if (!$aValue) {
                    continue;
                }

                $aShift = array_shift($aValue);
                for ($sCol = 1; $sCol <= 10; $sCol ++)
                {
                    switch ($sCol)
                    {
                        case 1:
                        case 2: $sWidth = $aPoint[sprintf('cellWidth%d', $sCol)]; break;
                        default: $sWidth = $aPoint['cellWidthOther']; break;
                    }
                    $sOption = 'colwidth=%s rowheight=%s fittextline={font=%s fontsize=7 fitmethod=auto position={center}}';
                    $sOption = sprintf($sOption, $sWidth, $aPoint['cellHeight'], $this->aOption['font'][($sCol == 2) ? 'arial_bd' : 'arial']);
                    $sResult = $oCatalog->addTableCell($sResult, $sCol, $sRow, $aShift[sprintf('col%d', $sCol)] ?? '', $sOption);
                }
            }
            $sOption = 'header=0 rowheightdefault=auto stroke={{line=frame linewidth=1 strokecolor=%s} {line=other linewidth=0.1}} fill={{area=roweven fillcolor=%s}}';
            $sOption = sprintf($sOption, $this->aOption['colors']['line'], $this->aOption['colors']['back']);
            $oCatalog->fit_table($sResult, $aPoint['table2']['x1'], $aPoint['table2']['y1'], $aPoint['table2']['x2'], $aPoint['table2']['y2'] - $aPoint['cellHeight'] * 2, $sOption);

            $oCatalog = $this->pagination($oCatalog, $this->aOption['pagination']);
            $oCatalog->end_page_ext('');
            $this->aOption['pagination'] ++;
        }

        return $sBuffer ? ($this->aOption['pagination'] - 1) : $oCatalog;
    }


    /**
     * 驱动轴参数页1(Joint,Propeller Shaft)
     *
     * @param PDFlib $oCatalog
     * @param array $aValue  数据
     * @param false $sBuffer 是否只返回页码
     *
     * @example
     * [
     *      'style' => 'propellerShaftByDrive', // 版式
     *      'title' => 'Joint,Propeller Shaft', // 标题
     *      'value' => [
     *          ['col1' => 'Joint,Propelle', 'col2' => '510434S', 'col3' => 6, 'col4' => 97, 'col5'=> 10, 'col6' => 90, 'col7' => 37.4, 'col8' => 90],
     *          // ...
     *      ]
     * ]
     *
     * @return int|PDFlib
     */
    public function propellerShaftByDrive(PDFlib $oCatalog, array $aValue, bool $sBuffer = false)
    {
        $aPoint = [
            'x1' => 60,
            'x2' => 544,
            
            'headerY1' => 788,
            'headerY2' => 765,
            
            'cellWidth1' => 90,
            'cellWidth2' => 75,
            'cellHeight' => 11, // 表格高度
        ];
        $aPoint['cellWidth'] = $aPoint['x2'] - $aPoint['x1'];
        $aPoint['cellWidthOther'] = $aPoint['cellWidth'] / 6;
        
        $aPoint['table1'] = [
            'x1' => $aPoint['x1'],
            'y1' => $aPoint['headerY2'] - 129,
            'x2' => $aPoint['x2'],
            'y2' => $aPoint['headerY2'],
        ];
        
        $aPoint['table2'] = [
            'x1' => $aPoint['x1'],
            'y1' => $this->aOption['point']['y1'],
            'x2' => $aPoint['x2'],
            'y2' => $aPoint['table1']['y1']
        ];
        
        // 内容页面
        $sData = 0;
        $sTake = 51;
        $sTitle = $aValue['title'];
        $sRemark = $aValue['remark'] ?? '';
        $aValue = $aValue['value'];
        $sSkip = ceil(count($aValue) / $sTake);
        for ($sPage = 1; $sPage <= $sSkip; $sPage ++)
        {
            $oCatalog->begin_page_ext(0, 0, 'width=a4.width height=a4.height');
            if (!$sData && $sRemark) {
                $oCatalog->create_bookmark($sRemark, sprintf('parent=%d', 0));$sData = 1;
            }
            
            // 页头设置
            $sOption = 'fontname={font/arial_bd} embedding fontsize=24 encoding=unicode fillcolor=%s';
            $sOption = sprintf($sOption, $this->aOption['colors']['font']);
            $oCatalog->fit_textline($sTitle, $aPoint['x1'], $aPoint['headerY1'], $sOption);
            
            $sOption = 'fontname={font/arial} embedding fontsize=14 encoding=unicode fillcolor=%s';
            $sOption = sprintf($sOption, $this->aOption['colors']['font']);
            $oCatalog->fit_textline(sprintf('Basic Dimension Table %s to Dimension………………………………………………', $this->aOption['ver']), $aPoint['x1'], $aPoint['headerY2'], $sOption);
            
            $sResult = 0;
            $oImage = $oCatalog->loadImage('auto', $this->aOption['image']['propellerShaftByDrive1'], '');
            $sOption = sprintf('image=%s fitimage={position={center}} margin=5', $oImage);
            $sResult = $oCatalog->addTableCell($sResult, 1, 1, '', $sOption);
            
            $sOption = 'header=0 rowheightdefault=auto';
            $oCatalog->fit_table($sResult, $aPoint['table1']['x1'], $aPoint['table1']['y1'], $aPoint['table1']['x2'], $aPoint['table1']['y2'], $sOption);
            
            // 内容
            // 解决头部粗线问题
            $sCell = 0;
            $aCell = [
                1 => [1 => [1, 2, 2, 'Product'], 2 => [1, 2, 2, $this->aOption['gTitle']], 3 => [6, 1, 1, 'BASIC DIMENSIONS(mm)']],
                2 => [3 => [1, 1, 1, 'A'], 4 => [1, 1, 1, 'B'], 5 => [1, 1, 1, 'C'], 6 => [1, 1, 1, 'H'], 7 => [1, 1, 1, 'L'], 8 => [1, 1, 1, 'P']],
            ];
            $sResult = 0;
            foreach ($aCell as $sRow =>$aItem)
            {
                foreach ($aItem as $sCol => $aData)
                {
                    switch ($sCol)
                    {
                        case 1:
                        case 2: $sWidth = $aPoint[sprintf('cellWidth%d', $sCol)]; break;
                        default: $sWidth = $aPoint['cellWidthOther']; break;
                    }
                    if (($sRow == 1) && ($sCol == 3)) {
                        $sWidth = $sWidth * 5;
                    }
                    
                    $sOption = 'colwidth=%s rowheight=%s fittextline={font=%s fontsize=9 fitmethod=auto fillcolor=%s position={center}} colspan=%d rowspan=%d';
                    $sOption = sprintf($sOption, $sWidth, $aPoint['cellHeight'] * $aData[2], $this->aOption['font']['arial_bd'], $this->aOption['colors']['font'], $aData[0], $aData[1]);
                    $sCell = $oCatalog->addTableCell($sCell, $sCol, $sRow, $aData[3], $sOption);
                }
            }
            $sOption = 'header=0 rowheightdefault=auto stroke={{line=other linewidth=1 strokecolor=%s}} fill={{area=table fillcolor=%s}}';
            $sOption = sprintf($sOption, $this->aOption['colors']['line'], $this->aOption['colors']['back']);
            $oCatalog->fit_table($sCell, $aPoint['table2']['x1'], $aPoint['table2']['y1'] - $aPoint['cellHeight'] * 2, $aPoint['table2']['x2'], $aPoint['table2']['y2'], $sOption);
            
            // 填充单元格
            for ($sRow = 1; $sRow <= 51; $sRow ++)
            {
                if (!$aValue) {
                    continue;
                }
                
                $aShift = array_shift($aValue);
                for ($sCol = 1; $sCol <= 8; $sCol ++)
                {
                    switch ($sCol)
                    {
                        case 1:
                        case 2: $sWidth = $aPoint[sprintf('cellWidth%d', $sCol)]; break;
                        default: $sWidth = $aPoint['cellWidthOther']; break;
                    }
                    $sOption = 'colwidth=%s rowheight=%s fittextline={font=%s fontsize=7 fitmethod=auto position={center}}';
                    $sOption = sprintf($sOption, $sWidth, $aPoint['cellHeight'], $this->aOption['font'][($sCol == 2) ? 'arial_bd' : 'arial']);
                    $sResult = $oCatalog->addTableCell($sResult, $sCol, $sRow, $aShift[sprintf('col%d', $sCol)] ?? '', $sOption);
                }
            }
            $sOption = 'header=0 rowheightdefault=auto stroke={{line=frame linewidth=1 strokecolor=%s} {line=other linewidth=0.1}} fill={{area=roweven fillcolor=%s}}';
            $sOption = sprintf($sOption, $this->aOption['colors']['line'], $this->aOption['colors']['back']);
            $oCatalog->fit_table($sResult, $aPoint['table2']['x1'], $aPoint['table2']['y1'], $aPoint['table2']['x2'], $aPoint['table2']['y2'] - $aPoint['cellHeight'] * 2, $sOption);
            
            $this->pagination($oCatalog, $this->aOption['pagination']);
            $oCatalog->end_page_ext('');
            $this->aOption['pagination'] ++;
        }
        
        return $sBuffer ? ($this->aOption['pagination'] - 1) : $oCatalog;
    }
    
    /**
     * 驱动轴参数页2(Propshaft)
     *
     * @param PDFlib $oCatalog
     * @param array $aValue  数据
     * @param false $sBuffer 是否只返回页码
     *
     * @example
     * [
     *      'style' => 'propShaftByDrive', // 版式
     *      'title' => 'Propshaft', // 标题
     *      'value' => [
     *          ['col1' => 'Propshaft', 'col2' => '201406', 'col3' => 6, 'col4' => 97, 'col5'=> 10, 'col6' => 90, 'col7' => 37.4],
     *          // ...
     *      ]
     * ]
     *
     * @return int|PDFlib
     */
    public function propShaftByDrive(PDFlib $oCatalog, array $aValue, bool $sBuffer = false)
    {
        $aPoint = [
            'x1' => 85,
            'x2' => 518,
            'headerY1' => 788,
            'headerY2' => 765,
            
            'cellWidth1' => 115,
            'cellWidth2' => 80,
            'cellHeight' => 11, // 表格高度
        ];
        $aPoint['cellWidth'] = $aPoint['x2'] - $aPoint['x1'];
        $aPoint['cellWidthOther'] = $aPoint['cellWidth'] / 5;
        
        $aPoint['table1'] = [
            'x1' => $aPoint['x1'],
            'y1' => $aPoint['headerY2'] - 129,
            'x2' => $aPoint['x2'],
            'y2' => $aPoint['headerY2'],
        ];
        
        $aPoint['table2'] = [
            'x1' => $aPoint['x1'],
            'y1' => $this->aOption['point']['y1'],
            'x2' => $aPoint['x2'],
            'y2' => $aPoint['table1']['y1']
        ];
        
        // 内容页面
        $sData = 0;
        $sTotal = 1;
        $sTake = 51;
        $sTitle = $aValue['title'];
        $sRemark = $aValue['remark'] ?? '';
        $aValue = $aValue['value'];
        $sSkip = ceil(count($aValue) / $sTake);
        for ($sPage = 1; $sPage <= $sSkip; $sPage ++)
        {
            $oCatalog->begin_page_ext(0, 0, 'width=a4.width height=a4.height');
            if (!$sData && $sRemark) {
                $oCatalog->create_bookmark($sRemark, sprintf('parent=%d', 0));$sData = 1;
            }
            
            // 页头设置
            $sOption = 'fontname={font/arial_bd} embedding fontsize=24 encoding=unicode fillcolor=%s';
            $sOption = sprintf($sOption, $this->aOption['colors']['font']);
            $oCatalog->fit_textline($sTitle, $aPoint['x1'], $aPoint['headerY1'], $sOption);
            
            $sOption = 'fontname={font/arial} embedding fontsize=14 encoding=unicode fillcolor=%s';
            $sOption = sprintf($sOption, $this->aOption['colors']['font']);
            $oCatalog->fit_textline(sprintf('Basic Dimension Table %s to Dimension………………………………………………', $this->aOption['ver']), $aPoint['x1'], $aPoint['headerY2'], $sOption);
            
            $sResult = 0;
            $oImage = $oCatalog->loadImage('auto', $this->aOption['image']['propellerShaftByDrive2'], '');
            $sOption = sprintf('image=%s fitimage={position={center}} margin=5', $oImage);
            $sResult = $oCatalog->addTableCell($sResult, 1, 1, '', $sOption);
            
            $sOption = 'header=0 rowheightdefault=auto';
            $oCatalog->fit_table($sResult, $aPoint['table1']['x1'], $aPoint['table1']['y1'], $aPoint['table1']['x2'], $aPoint['table1']['y2'], $sOption);
            
            // 内容
            // 解决头部粗线问题
            $sCell = 0;
            $aCell = [
                1 => [1 => [1, 2, 2, 'Product'], 2 => [1, 2, 2, $this->aOption['gTitle']], 3 => [5, 1, 1, 'BASIC DIMENSIONS(mm)']],
                2 => [3 => [1, 1, 1, 'A'], 4 => [1, 1, 1, 'B'], 5 => [1, 1, 1, 'C'], 6 => [1, 1, 1, 'D'], 7 => [1, 1, 1, 'H']],
            ];
            $sResult = 0;
            foreach ($aCell as $sRow =>$aItem)
            {
                foreach ($aItem as $sCol => $aData)
                {
                    switch ($sCol)
                    {
                        case 1:
                        case 2: $sWidth = $aPoint[sprintf('cellWidth%d', $sCol)]; break;
                        default: $sWidth = $aPoint['cellWidthOther']; break;
                    }
                    if (($sRow == 1) && ($sCol == 3)) {
                        $sWidth = $sWidth * 5;
                    }
                    
                    $sOption = 'colwidth=%s rowheight=%s fittextline={font=%s fontsize=9 fillcolor=%s fitmethod=auto position={center}} colspan=%d rowspan=%d';
                    $sOption = sprintf($sOption, $sWidth, $aPoint['cellHeight'] * $aData[2], $this->aOption['font']['arial_bd'], $this->aOption['colors']['font'], $aData[0], $aData[1]);
                    $sCell = $oCatalog->addTableCell($sCell, $sCol, $sRow, $aData[3], $sOption);
                }
            }
            $sOption = 'header=0 rowheightdefault=auto stroke={{line=other linewidth=1 strokecolor=%s}} fill={{area=table fillcolor=%s}}';
            $sOption = sprintf($sOption, $this->aOption['colors']['line'], $this->aOption['colors']['back']);
            $oCatalog->fit_table($sCell, $aPoint['table2']['x1'], $aPoint['table2']['y1'] - $aPoint['cellHeight'] * 2, $aPoint['table2']['x2'], $aPoint['table2']['y2'], $sOption);
            
            // 填充单元格
            for ($sRow = 1; $sRow <= 51; $sRow ++)
            {
                if (!$aValue) {
                    continue;
                }
                
                $aShift = array_shift($aValue);
                for ($sCol = 1; $sCol <= 7; $sCol ++)
                {
                    switch ($sCol)
                    {
                        case 1:
                        case 2: $sWidth = $aPoint[sprintf('cellWidth%d', $sCol)]; break;
                        default: $sWidth = $aPoint['cellWidthOther']; break;
                    }
                    $sOption = 'colwidth=%s rowheight=%s fittextline={font=%s fontsize=7 fitmethod=auto position={center}}';
                    $sOption = sprintf($sOption, $sWidth, $aPoint['cellHeight'], $this->aOption['font'][($sCol == 2) ? 'arial_bd' : 'arial']);
                    $sResult = $oCatalog->addTableCell($sResult, $sCol, $sRow, $aShift[sprintf('col%d', $sCol)] ?? '', $sOption);
                }
            }
            $sOption = 'header=0 rowheightdefault=auto stroke={{line=frame linewidth=1 strokecolor=%s} {line=other linewidth=0.1}} fill={{area=roweven fillcolor=%s}}';
            $sOption = sprintf($sOption, $this->aOption['colors']['line'], $this->aOption['colors']['back']);
            $oCatalog->fit_table($sResult, $aPoint['table2']['x1'], $aPoint['table2']['y1'], $aPoint['table2']['x2'], $aPoint['table2']['y2'] - $aPoint['cellHeight'] * 2, $sOption);
            
            $sTotal ++;
            $oCatalog = $this->pagination($oCatalog, $this->aOption['pagination']);
            $oCatalog->end_page_ext('');
            $this->aOption['pagination'] ++;
        }
        
        return $sBuffer ? ($this->aOption['pagination'] - 1) : $oCatalog;
    }
    
    /**
     * 轴承参数页1(Propshaft)
     *
     * @param PDFlib $oCatalog
     * @param array $aValue  数据
     * @param false $sBuffer 是否只返回页码
     *
     * @return int|PDFlib
     *@example
     * [
     *      'style' => 'clutchByBearing | tensionerByBearing', // 版式
     *      'title' => 'Propshaft', // 标题
     *      'value' => [
     *          ['col1' => $sRun, 'col2' => 97, 'col3' => 'Ф10.5(4)', 'col4' => '56', 'col5' => '..', 'col6' => '..'],
     *          // ...
     *      ]
     * ]
     *
     */
    public function clutchByBearing(PDFlib $oCatalog, array $aValue, bool $sBuffer = false)
    {
        $aPoint = [
            'x1' => 85,
            'x2' => 518,
            'headerY1' => 788,
            'headerY2' => 765,
            
            'cellWidth1' => 51,
            'cellWidth2' => 80,
            'cellHeight' => 11, // 表格高度
        ];
        $aPoint['cellWidth'] = $aPoint['x2'] - $aPoint['x1'];
        $aPoint['cellWidthOther'] = $aPoint['cellWidth'] / 5;
        
        $aPoint['table1'] = [
            'x1' => $aPoint['x1'],
            'y1' => $aPoint['headerY2'] - 129,
            'x2' => $aPoint['x2'],
            'y2' => $aPoint['headerY2'],
        ];
        
        $aPoint['table2'] = [
            'x1' => $aPoint['x1'],
            'y1' => $this->aOption['point']['y1'],
            'x2' => $aPoint['x2'],
            'y2' => $aPoint['table1']['y1']
        ];
        
        $sStyle = $aValue['style'];
        switch ($sStyle)
        {
            case 'tensionerByBearing':
                $aStyle = [
                    'about' => $this->aOption['image']['tensionerByBearing'],
                    'cell' => [
                        1 => [1 => [1, 2, 2, 'ID'], 2 => [1, 2, 2, $this->aOption['gTitle']], 3 => [4, 1, 1, 'BASIC DIMENSIONS(mm)']],
                        2 => [3 => [1, 1, 1, 'D'], 4 => [1, 1, 1, 'd'], 5 => [1, 1, 1, 'H'], 6 => [1, 1, 1, 'h']],
                    ]
                ];
                break;
            
            default:
                $aStyle = [
                    'about' => $this->aOption['image']['clutchByBearing'],
                    'cell' => [
                        1 => [1 => [1, 2, 2, 'ID'], 2 => [1, 2, 2, $this->aOption['gTitle']], 3 => [4, 1, 1, 'BASIC DIMENSIONS(mm)']],
                        2 => [3 => [1, 1, 1, 'D'], 4 => [1, 1, 1, 'd'], 5 => [1, 1, 1, 'W'], 6 => [1, 1, 1, 'h']],
                    ]
                ];
                break;
        }
        
        // 内容页面
        $sData = 0;
        $sTotal = 1;
        $sTake = 51;
        $sTitle = $aValue['title'];
        $sRemark = $aValue['remark'] ?? '';
        $aValue = $aValue['value'];
        $sSkip = ceil(count($aValue) / $sTake);
        for ($sPage = 1; $sPage <= $sSkip; $sPage ++)
        {
            $oCatalog->begin_page_ext(0, 0, 'width=a4.width height=a4.height');
            if (!$sData && $sRemark) {
                $oCatalog->create_bookmark($sRemark, sprintf('parent=%d', 0));$sData = 1;
            }
            
            // 页头设置
            $sOption = 'fontname={font/arial_bd} embedding fontsize=24 encoding=unicode fillcolor=%s';
            $sOption = sprintf($sOption, $this->aOption['colors']['font']);
            $oCatalog->fit_textline($sTitle, $aPoint['x1'], $aPoint['headerY1'], $sOption);
            
            $sOption = 'fontname={font/arial} embedding fontsize=14 encoding=unicode fillcolor=%s';
            $sOption = sprintf($sOption, $this->aOption['colors']['font']);
            $oCatalog->fit_textline(sprintf('Basic Dimension Table %s to Dimension………………………………………………', $this->aOption['ver']), $aPoint['x1'], $aPoint['headerY2'], $sOption);
            
            $sResult = 0;
            $oImage = $oCatalog->loadImage('auto', $aStyle['about'], '');
            $sOption = sprintf('image=%s fitimage={position={center}} margin=5', $oImage);
            $sResult = $oCatalog->addTableCell($sResult, 1, 1, '', $sOption);
            
            $sOption = 'header=0 rowheightdefault=auto';
            $oCatalog->fit_table($sResult, $aPoint['table1']['x1'], $aPoint['table1']['y1'], $aPoint['table1']['x2'], $aPoint['table1']['y2'], $sOption);
            
            // 内容
            // 解决头部粗线问题
            $sCell = 0;
            $aCell = $aStyle['cell'];
            $sResult = 0;
            foreach ($aCell as $sRow =>$aItem)
            {
                foreach ($aItem as $sCol => $aData)
                {
                    switch ($sCol)
                    {
                        case 1:
                        case 2: $sWidth = $aPoint[sprintf('cellWidth%d', $sCol)]; break;
                        default: $sWidth = $aPoint['cellWidthOther']; break;
                    }
                    if (($sRow == 1) && ($sCol == 3)) {
                        $sWidth = $sWidth * 4;
                    }
                    
                    $sOption = 'colwidth=%s rowheight=%s fittextline={font=%s fontsize=9 fillcolor=%s fitmethod=auto position={center}} colspan=%d rowspan=%d';
                    $sOption = sprintf($sOption, $sWidth, $aPoint['cellHeight'] * $aData[2], $this->aOption['font']['arial_bd'], $this->aOption['colors']['font'], $aData[0], $aData[1]);
                    $sCell = $oCatalog->addTableCell($sCell, $sCol, $sRow, $aData[3], $sOption);
                }
            }
            $sOption = 'header=0 rowheightdefault=auto stroke={{line=other linewidth=1 strokecolor=%s}} fill={{area=table fillcolor=%s}}';
            $sOption = sprintf($sOption, $this->aOption['colors']['line'], $this->aOption['colors']['back']);
            $oCatalog->fit_table($sCell, $aPoint['table2']['x1'], $aPoint['table2']['y1'] - $aPoint['cellHeight'] * 2, $aPoint['table2']['x2'], $aPoint['table2']['y2'], $sOption);
            
            // 填充单元格
            for ($sRow = 1; $sRow <= 51; $sRow ++)
            {
                if (!$aValue) {
                    continue;
                }
                
                $aShift = array_shift($aValue);
                for ($sCol = 1; $sCol <= 6; $sCol ++)
                {
                    switch ($sCol)
                    {
                        case 1:
                        case 2: $sWidth = $aPoint[sprintf('cellWidth%d', $sCol)]; break;
                        default: $sWidth = $aPoint['cellWidthOther']; break;
                    }
                    $sOption = 'colwidth=%s rowheight=%s fittextline={font=%s fontsize=7 fitmethod=auto position={center}}';
                    $sOption = sprintf($sOption, $sWidth, $aPoint['cellHeight'], $this->aOption['font'][($sCol == 2) ? 'arial_bd' : 'arial']);
                    $sResult = $oCatalog->addTableCell($sResult, $sCol, $sRow, $aShift[sprintf('col%d', $sCol)] ?? '', $sOption);
                }
            }
            $sOption = 'header=0 rowheightdefault=auto stroke={{line=frame linewidth=1 strokecolor=%s} {line=other linewidth=0.1}} fill={{area=roweven fillcolor=%s}}';
            $sOption = sprintf($sOption, $this->aOption['colors']['line'], $this->aOption['colors']['back']);
            $oCatalog->fit_table($sResult, $aPoint['table2']['x1'], $aPoint['table2']['y1'], $aPoint['table2']['x2'], $aPoint['table2']['y2'] - $aPoint['cellHeight'] * 2, $sOption);
            
            $sTotal ++;
            $oCatalog = $this->pagination($oCatalog, $this->aOption['pagination']);
            $oCatalog->end_page_ext('');
            $this->aOption['pagination'] ++;
        }
        
        return $sBuffer ? ($this->aOption['pagination'] - 1) : $oCatalog;
    }
    
    /**
     * 配件工具页1
     *
     * @param PDFlib $oCatalog
     * @param array $aValue  数据
     * @param false $sBuffer 是否只返回页码
     *
     * @example
     * [
     *      'style' => 'tools1Guide', // 版式
     *      'title' => 'Hub Assemblies | BraKe Disc/Brake Drum | Drive Shaft', // 标题
     *      'value' => [
     *          ['col1' => 1, 'col2' => '9336017K', 'col3' => 1, 'col4' => 2, 'col5' => 3, 'col6' => 4, 'col7' => 5, 'col8' => 6, 'col9' => 7, 'col10' => 8, 'col11' => 9, 'col12' => 10, 'col13' => 11, 'col14' => 12],
     *          ['col1' => 2, 'col2' => '9336017K', 'col3' => 1, 'col4' => 2, 'col5' => 3, 'col6' => 4, 'col7' => 5, 'col8' => 6, 'col9' => 7, 'col10' => 8, 'col11' => 9, 'col12' => 10, 'col13' => 11, 'col14' => 12],
     *          ...
     *      ]
     * ]
     *
     * @return int|PDFlib
     */
    public function tools1Guide(PDFlib $oCatalog, array $aValue, bool $sBuffer = false)
    {
        $sTake = 64;
        $aPoint = array_merge($this->aOption['point'], [
            'headerY1' => 788,
            'headerY2' => 768,
            'y2' => 758,
            
            'cellWidth1' => 23,
            'cellWidth2' => 54,
            'cellWidth3' => 50,
            'cellHeight' => 11, // 表格高度
        ]);
        $aPoint['cellWidthOther'] = ($this->aOption['point']['x2'] - $this->aOption['point']['x1'] - $aPoint['cellWidth1'] - $aPoint['cellWidth2'] - $aPoint['cellWidth3']) / 12;
        
        $aImage = [3 => 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12];
        foreach ($aImage as $sKey => $sVal) {
            $aImage[$sKey] = sprintf('%s/image/tools1/%s.png', $this->aOption['resources'], $sVal);
        }
        
        // 内容页面
        $sData = 0;
        $aText = [1 => 'ID', $this->aOption['gTitle'], 15 => 'OTHERS'];
        $sTitle = $aValue['title'];
        $sRemark = $aValue['remark'] ?? '';
        $aValue = $aValue['value'];
        $sSkip = ceil(count($aValue) / $sTake);
        for ($sPage = 1; $sPage <= $sSkip; $sPage ++)
        {
            $oCatalog->begin_page_ext(0, 0, 'width=a4.width height=a4.height');
            if (!$sData && $sRemark) {
                $oCatalog->create_bookmark($sRemark, sprintf('parent=%d', 0));$sData = 1;
            }
            
            // 页头设置
            $sOption = 'fontname={font/arial_bd} embedding fontsize=24 encoding=unicode fillcolor=%s';
            $sOption = sprintf($sOption, $this->aOption['colors']['font']);
            $oCatalog->fit_textline($sTitle, $this->aOption['point']['x1'], $aPoint['headerY1'], $sOption);
            
            $sOption = 'fontname={font/arial} embedding fontsize=14 encoding=unicode fillcolor=%s';
            $sOption = sprintf($sOption, $this->aOption['colors']['font']);
            $oCatalog->fit_textline('Contents of Complete Kits……………………………………………………………………', $this->aOption['point']['x1'], $aPoint['headerY2'], $sOption);
            
            // 解决头部粗线问题
            $sCell = 0;
            for ($sCol = 1; $sCol <= 15; $sCol ++)
            {
                $sWidth = $aPoint[sprintf('cellWidth%d', $sCol)] ?? $aPoint['cellWidthOther'];
                switch ($sCol)
                {
                    case 1:
                    case 2:
                    case 15:
                        $sValue = $aText[$sCol];
                        $sOption = 'colwidth=%s rowheight=%s fittextline={font=%s fontsize=10 fillcolor=%s fitmethod=auto position=center} matchbox={fillcolor=%s} margin=2';
                        $sOption = sprintf($sOption, $sWidth, $aPoint['cellHeight'] * 3, $this->aOption['font']['arial_bd'], $this->aOption['colors']['line'], $this->aOption['colors']['back']);
                        break;
                    
                    default:
                        $sValue = '';
                        $oImage = $oCatalog->loadImage('auto', $aImage[$sCol], '');
                        $sOption = 'colwidth=%s rowheight=%s margin=3 image=%s fitimage={position={center}}';
                        $sOption = sprintf($sOption, $sWidth, $aPoint['cellHeight'] * 3, $oImage);
                        break;
                }
                
                $sCell = $oCatalog->addTableCell($sCell, $sCol, 1, $sValue, $sOption);
            }
            $sOption = 'header=0 rowheightdefault=auto stroke={{line=other linewidth=1 strokecolor=%s}}';
            $sOption = sprintf($sOption, $this->aOption['colors']['line']);
            $oCatalog->fit_table($sCell, $aPoint['x1'], $aPoint['y2'] - $aPoint['cellHeight'] * 3, $aPoint['x2'], $aPoint['y2'], $sOption);
            
            // 绘制表格
            $sResult = 0;
            for ($sRow = 1; $sRow <= 61; $sRow ++)
            {
                if (!$aValue) {
                    continue;
                }
                
                $aShift = array_shift($aValue);
                for ($sCol = 1; $sCol <= 15; $sCol ++)
                {
                    $sWidth = $aPoint[sprintf('cellWidth%d', $sCol)] ?? $aPoint['cellWidthOther'];
                    $sOption = 'colwidth=%s rowheight=%s fittextline={font=%s fontsize=8 fitmethod=auto position=center}';
                    $sOption = sprintf($sOption, $sWidth, $aPoint['cellHeight'], $this->aOption['font'][($sCol == 2) ? 'arial_bd' : 'arial']);
                    $sResult = $oCatalog->addTableCell($sResult, $sCol, $sRow, $aShift[sprintf('col%d', $sCol)], $sOption);
                }
            }
            
            // 生成表格
            $sOption = 'header=0 rowheightdefault=auto stroke={{line=other linewidth=0.1} {line=frame linewidth=1 strokecolor=%s}} fill={{area=roweven fillcolor=%s}}';
            $sOption = sprintf($sOption, $this->aOption['colors']['line'], $this->aOption['colors']['back']);
            $oCatalog->fit_table($sResult, $aPoint['x1'], $aPoint['y1'], $aPoint['x2'], $aPoint['y2'] - $aPoint['cellHeight'] * 3, $sOption);
            
            $oCatalog = $this->pagination($oCatalog, $this->aOption['pagination']);
            $oCatalog->end_page_ext('');
            $this->aOption['pagination'] ++;
        }
        
        return $sBuffer ? ($this->aOption['pagination'] - 1) : $oCatalog;
    }

    /**
     * 配件工具页1
     *
     * @param PDFlib $oCatalog
     * @param array $aValue  数据
     * @param false $sBuffer 是否只返回页码
     *
     * @example
     * [
     *      'style' => 'tools1Guide', // 版式
     *      'title' => 'Hub Assemblies | BraKe Disc/Brake Drum | Drive Shaft', // 标题
     *      'value' => [
     *          ['col1' => 1, 'col2' => '9336017K', 'col3' => 1, 'col4' => 2, 'col5' => 3, 'col6' => 4, 'col7' => 5, 'col8' => 6, 'col9' => 7, 'col10' => 8, 'col11' => 9, 'col12' => 10, 'col13' => 11, 'col14' => 12],
     *          ['col1' => 2, 'col2' => '9336017K', 'col3' => 1, 'col4' => 2, 'col5' => 3, 'col6' => 4, 'col7' => 5, 'col8' => 6, 'col9' => 7, 'col10' => 8, 'col11' => 9, 'col12' => 10, 'col13' => 11, 'col14' => 12],
     *          ...
     *      ]
     * ]
     *
     * @return int|PDFlib
     */
    public function tools2Guide(PDFlib $oCatalog, array $aValue, bool $sBuffer = false)
    {
        $sTake = 64;
        $aPoint = array_merge($this->aOption['point'], [
            'headerY1' => 788,
            'headerY2' => 768,
            'y2' => 758,

            'cellWidth1' => 23,
            'cellWidth2' => 54,
            'cellWidth3' => 50,
            'cellHeight' => 11, // 表格高度
        ]);
        $aPoint['cellWidthOther'] = ($this->aOption['point']['x2'] - $this->aOption['point']['x1'] - $aPoint['cellWidth1'] - $aPoint['cellWidth2'] - $aPoint['cellWidth3']) / 13;

        $aImage = [3 => 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13];
        foreach ($aImage as $sKey => $sVal) {
            $aImage[$sKey] = sprintf('%s/image/tools2/%s.png', $this->aOption['resources'], $sVal);
        }

        // 内容页面
        $sData = 0;
        $aText = [1 => 'ID', $this->aOption['gTitle'], 16 => 'OTHERS'];
        $sTitle = $aValue['title'];
        $sRemark = $aValue['remark'] ?? '';
        $aValue = $aValue['value'];
        $sSkip = ceil(count($aValue) / $sTake);
        for ($sPage = 1; $sPage <= $sSkip; $sPage ++)
        {
            $oCatalog->begin_page_ext(0, 0, 'width=a4.width height=a4.height');
            if (!$sData && $sRemark) {
                $oCatalog->create_bookmark($sRemark, sprintf('parent=%d', 0));$sData = 1;
            }

            // 页头设置
            $sOption = 'fontname={font/arial_bd} embedding fontsize=24 encoding=unicode fillcolor=%s';
            $sOption = sprintf($sOption, $this->aOption['colors']['font']);
            $oCatalog->fit_textline($sTitle, $this->aOption['point']['x1'], $aPoint['headerY1'], $sOption);

            $sOption = 'fontname={font/arial} embedding fontsize=14 encoding=unicode fillcolor=%s';
            $sOption = sprintf($sOption, $this->aOption['colors']['font']);
            $oCatalog->fit_textline('Contents of Complete Kits……………………………………………………………………', $this->aOption['point']['x1'], $aPoint['headerY2'], $sOption);

            // 解决头部粗线问题
            $sCell = 0;
            for ($sCol = 1; $sCol <= 16; $sCol ++)
            {
                $sWidth = $aPoint[sprintf('cellWidth%d', $sCol)] ?? $aPoint['cellWidthOther'];
                switch ($sCol)
                {
                    case 1:
                    case 2:
                    case 16:
                        $sValue = $aText[$sCol];
                        $sOption = 'colwidth=%s rowheight=%s fittextline={font=%s fontsize=10 fillcolor=%s fitmethod=auto position=center} matchbox={fillcolor=%s} margin=2';
                        $sOption = sprintf($sOption, $sWidth, $aPoint['cellHeight'] * 3, $this->aOption['font']['arial_bd'], $this->aOption['colors']['line'], $this->aOption['colors']['back']);
                        break;

                    default:
                        $sValue = '';
                        $oImage = $oCatalog->loadImage('auto', $aImage[$sCol], '');
                        $sOption = 'colwidth=%s rowheight=%s margin=3 image=%s fitimage={position={center}}';
                        $sOption = sprintf($sOption, $sWidth, $aPoint['cellHeight'] * 3, $oImage);
                        break;
                }

                $sCell = $oCatalog->addTableCell($sCell, $sCol, 1, $sValue, $sOption);
            }
            $sOption = 'header=0 rowheightdefault=auto stroke={{line=other linewidth=1 strokecolor=%s}}';
            $sOption = sprintf($sOption, $this->aOption['colors']['line']);
            $oCatalog->fit_table($sCell, $aPoint['x1'], $aPoint['y2'] - $aPoint['cellHeight'] * 3, $aPoint['x2'], $aPoint['y2'], $sOption);

            // 绘制表格
            $sResult = 0;
            for ($sRow = 1; $sRow <= 61; $sRow ++)
            {
                if (!$aValue) {
                    continue;
                }

                $aShift = array_shift($aValue);
                for ($sCol = 1; $sCol <= 16; $sCol ++)
                {
                    $sWidth = $aPoint[sprintf('cellWidth%d', $sCol)] ?? $aPoint['cellWidthOther'];
                    $sOption = 'colwidth=%s rowheight=%s fittextline={font=%s fontsize=8 fitmethod=auto position=center}';
                    $sOption = sprintf($sOption, $sWidth, $aPoint['cellHeight'], $this->aOption['font'][($sCol == 2) ? 'arial_bd' : 'arial']);
                    $sResult = $oCatalog->addTableCell($sResult, $sCol, $sRow, $aShift[sprintf('col%d', $sCol)], $sOption);
                }
            }

            // 生成表格
            $sOption = 'header=0 rowheightdefault=auto stroke={{line=other linewidth=0.1} {line=frame linewidth=1 strokecolor=%s}} fill={{area=roweven fillcolor=%s}}';
            $sOption = sprintf($sOption, $this->aOption['colors']['line'], $this->aOption['colors']['back']);
            $oCatalog->fit_table($sResult, $aPoint['x1'], $aPoint['y1'], $aPoint['x2'], $aPoint['y2'] - $aPoint['cellHeight'] * 3, $sOption);

            $oCatalog = $this->pagination($oCatalog, $this->aOption['pagination']);
            $oCatalog->end_page_ext('');
            $this->aOption['pagination'] ++;
        }

        return $sBuffer ? ($this->aOption['pagination'] - 1) : $oCatalog;
    }

    /**
     * 轮毂车型应用页
     *
     * @param PDFlib $oCatalog
     * @param array $aValue  数据
     * @param false $sBuffer 是否只返回车型索引页数据 和 车型应用页页码
     *
     * @example
     * [
     *      'style' => 'modelGuideByWheel', // 版式
     *      'value' => [
     *          [
     *              'make' => 'AUDI',
     *              'model1' => 'A3 (8V1, 8VK)',
     *              'model2' => '1.8 TFSI quattro (132 kw)',
     *              'value' => [
     *                  ['col1' => '1990.12-1994.07', 'col2' => 'Saloon 937 A2.000', 'col3' => 'Date from:2004.10', 'col4' => 'R', 'col5' => 'L/R', 'col6' => '9230118K', 'col7' => '√'],
     *                  ['col1' => '1990.12-1994.07', 'col2' => 'Saloon 937 A2.000', 'col3' => 'Date from:2004.10', 'col4' => 'R', 'col5' => 'L/R', 'col6' => '9230118K', 'col7' => '√'],
     *                  ['col1' => '1990.12-1994.07', 'col2' => 'Saloon 937 A2.000', 'col3' => 'Date from:2004.10', 'col4' => 'R', 'col5' => 'L/R', 'col6' => '9230118K', 'col7' => '√'],
     *              ]
     *          ],
     *          [
     *              'make' => 'ACURA',
     *              'model1' => 'RDX',
     *              'model2' => '2.4 i-VTEC (153 kw)',
     *              'value' => [
     *                  ['col1' => '1990.12-1994.07', 'col2' => 'Saloon 937 A2.000', 'col3' => 'Date from:2004.10', 'col4' => 'R', 'col5' => 'L/R', 'col6' => '9230118K', 'col7' => '√'],
     *                  ['col1' => '1990.12-1994.07', 'col2' => 'Saloon 937 A2.000', 'col3' => 'Date from:2004.10', 'col4' => 'R', 'col5' => 'L/R', 'col6' => '9230118K', 'col7' => '√'],
     *                  ['col1' => '1990.12-1994.07', 'col2' => 'Saloon 937 A2.000', 'col3' => 'Date from:2004.10', 'col4' => 'R', 'col5' => 'L/R', 'col6' => '9230118K', 'col7' => '√'],
     *              ]
     *          ],
     *          ....
     *      ]
     * ]
     *
     * @return array|PDFlib
     */
    public function modelGuideByWheel(PDFlib $oCatalog, array $aValue, bool $sBuffer = false)
    {
        $aPoint = [
            'cellWidth' => $this->aOption['point']['x2'] - $this->aOption['point']['x1'],
            'cellWidth1' => 120, // 车型列宽度
            'cellWidth2' => 55, // 年份列宽度
            'cellWidth3' => 125, //
            'cellWidth4' => 100, //
            'cellWidth5' => 25, //
            'cellWidth6' => 25, //
            'cellWidth7' => 50, //
            'cellWidth8' => 25, //
            'cellHeight' => 11, // 表格高度
            
            'car' => sprintf('%s/image/%s/wheelCar.png', $this->aOption['resources'], $this->aOption['color']),
            'year' => sprintf('%s/image/%s/wheelYear.png', $this->aOption['resources'], $this->aOption['color']),
        ];
        
        // 内容页面
        $sRow = 1;
        $sRaw = 1;
        $sMake = '';
        $sModel = '';
        $sData = true;
        $sWhile = true;
        $aVehicle = [];
        $sParent = 0;
        $sResult = 0;
        
        $sRemark = $aValue['remark'] ?? '';
        $aValue = $aValue['value'];
        $aBookmark = ['make' => '', 'model' => '', 'current' => 0];
        $aMatch = [1 => '', 'YEAR', 'BODY STYLE & DRIVE TYPE & ENGINE', 'REMARKS', 'F/R', ' L/R', $this->aOption['gTitle'], 'ABS'];
        while ($sWhile)
        {
            // 页面开始
            if ($sRow == 1)
            {
                $sData = true;
                $sResult = 0;
                $oCatalog->begin_page_ext(0, 0, 'width=a4.width height=a4.height');
                
                // 分部书签
                if (!$sParent && $sRemark) {
                    $sParent = $oCatalog->create_bookmark($sRemark, sprintf('parent=%d', 0));
                }
                
                // 解决头部竖线变粗
                $sCell = 0;
                for ($sCol = 1; $sCol <= 8; $sCol ++)
                {
                    switch ($sCol)
                    {
                        case 1:
                            $oImage = $oCatalog->loadImage('auto', $aPoint['car'], '');
                            $sOption = 'colwidth=%s rowheight=%s image=%s fitimage={position={center}} fittextline={font=%s fontsize=9 fitmethod=auto} matchbox={fillcolor=%s}';
                            $sOption = sprintf($sOption, $aPoint[sprintf('cellWidth%d', $sCol)], $aPoint['cellHeight'] * 4, $oImage, $this->aOption['font']['arial_bd'], $this->aOption['colors']['back']);
                            break;
                        
                        case 2:
                            $oImage = $oCatalog->loadImage('auto', $aPoint['year'], '');
                            $sOption = 'colwidth=%s rowheight=%s image=%s fitimage={position={center bottom}} fittextline={font=%s fontsize=8 fitmethod=auto fillcolor=%s position={center bottom}} margin=5';
                            $sOption = sprintf($sOption, $aPoint[sprintf('cellWidth%d', $sCol)], $aPoint['cellHeight'] * 4, $oImage, $this->aOption['font']['arial_bd'], $this->aOption['colors']['font']);
                            break;
                        
                        case 3:
                        case 4:
                        case 5:
                        case 6:
                        case 8:
                            $sOption = 'colwidth=%s rowheight=%s fittextline={font=%s fontsize=%s fillcolor=%s fitmethod=auto}';
                            $sOption = sprintf($sOption, $aPoint[sprintf('cellWidth%d', $sCol)], $aPoint['cellHeight'] * 4, $this->aOption['font']['arial_bd'], ($sCol == 3) ? 6 : 9, $this->aOption['colors']['font']);
                            break;
                        
                        case 7:
                            $sOption = 'colwidth=%s rowheight=%s fittextline={font=%s fontsize=9 fillcolor=%s fitmethod=auto} matchbox={fillcolor=%s}';
                            $sOption = sprintf($sOption, $aPoint[sprintf('cellWidth%d', $sCol)], $aPoint['cellHeight'] * 4, $this->aOption['font']['arial_bd'], $this->aOption['colors']['line'], $this->aOption['colors']['back']);
                            break;
                        
                        default: $sOption = ''; break;
                    }
                    
                    $sCell = $oCatalog->addTableCell($sCell, $sCol, $sRow, $aMatch[$sCol], $sOption);
                }
                $sOption = 'header=0 rowheightdefault=auto stroke={{line=other linewidth=1 strokecolor=%s}}';
                $sOption = sprintf($sOption, $this->aOption['colors']['line']);
                $oCatalog->fit_table($sCell, $this->aOption['point']['x1'], $this->aOption['point']['y2'] - $aPoint['cellHeight'] * 4, $this->aOption['point']['x2'], $this->aOption['point']['y2'], $sOption);
                
                $sOption = 'rowheight=%s fittextline={font=%s fontsize=7 fillcolor=%s fitmethod=auto} colspan=8';
                $sOption = sprintf($sOption, $aPoint['cellHeight'] * 4, $this->aOption['font']['arial_bd'], $this->aOption['colors']['font']);
                $sResult = $oCatalog->addTableCell($sResult, 1, $sRow, '', $sOption);
                
                $sRow ++;
                $sRaw = $sRaw + 4;
            }
            $aShift = array_shift($aValue);
            
            // 车型列
            if ($sMake != $aShift['make'])
            {
                if ($sRaw >= 67) {
                    $sData = false;
                }
    
                if ($sData)
                {
                    foreach ([1, 2, 7, 8] as $sCol)
                    {
                        switch ($sCol)
                        {
                            case 1:
                                // 解决超出问题
                                $sChild = 0;
                                $sOption = 'colwidth=%s rowheight=%s fittextline={font=%s fontsize=10 fitmethod=auto position={left center}} matchbox={fillcolor=%s} margin=2';
                                $sOption = sprintf($sOption, $aPoint['cellWidth1'], $aPoint['cellHeight'], $this->aOption['font']['arial_bd'], $this->aOption['colors']['back']);
                                $sChild = $oCatalog->addTableCell($sChild, 1, 1, $aShift['make'], $sOption);
    
                                $sOption = 'colwidth=%s rowheight=%s fittextline={font=%s fontsize=8 fitmethod=auto position={left center}} matchbox={fillcolor=%s} margin=2';
                                $sOption = sprintf($sOption, $aPoint['cellWidth1'], $aPoint['cellHeight'], $this->aOption['font']['arial_bd'], $this->aOption['colors']['back']);
                                $sChild = $oCatalog->addTableCell($sChild, 1, 2, $aShift['model1'], $sOption);
                                
                                $sOption = 'header=0 rowheightdefault=auto stroke={{line=other linewidth=0}}';
                                $sChild = $oCatalog->fit_table(
                                    $sChild,
                                    $this->aOption['point']['x1'],
                                    $this->aOption['point']['y2'] - ($sRaw + 1) * $aPoint['cellHeight'],
                                    $this->aOption['point']['x1'] + $aPoint['cellWidth1'],
                                    $this->aOption['point']['y2'] - ($sRaw - 1) * $aPoint['cellHeight'],
                                    $sOption
                                );

                                $sOption = 'colwidth=%s rowheight=%s';
                                $sOption = sprintf($sOption, $aPoint[sprintf('cellWidth%d', $sCol)], $aPoint['cellHeight'] * 2);
                                break;
            
                            case 7:
                                $sOption = 'colwidth=%s rowheight=%s fittextline={font=%s fontsize=14 fitmethod=auto position={left center}} margin=2 matchbox={fillcolor=%s}';
                                $sOption = sprintf($sOption, $aPoint[sprintf('cellWidth%d', $sCol)], $aPoint['cellHeight'] * 2, $this->aOption['font']['arial_bd'], $this->aOption['colors']['back']);
                                break;
    
                            case 2:
                                $sOption = 'colwidth=%s rowheight=%s colspan=5 fittextline={font=%s fontsize=8 fitmethod=auto} ';
                                $sOption = sprintf($sOption, $aPoint[sprintf('cellWidth%d', $sCol)], $aPoint['cellHeight'] * 2, $this->aOption['font']['arial_bd']);
                                break;
                                
                            default:
                                $sOption = 'colwidth=%s rowheight=%s fittextline={font=%s fontsize=8 fitmethod=auto fitmethod=auto} ';
                                $sOption = sprintf($sOption, $aPoint[sprintf('cellWidth%d', $sCol)], $aPoint['cellHeight'] * 2, $this->aOption['font']['arial_bd']);
                                break;
                        }
                        $sResult = $oCatalog->addTableCell($sResult, $sCol, $sRow, '', $sOption);
                    }
    
                    $sRow ++;
                    $sRaw = $sRaw + 2;
                    $sMake = $aShift['make'];
                    $sModel = $aShift['model1'];
                    if ($sMake != $aBookmark['make'])
                    {
                        $sBookmark = $oCatalog->create_bookmark($sMake, sprintf('parent=%d', $sParent));

                        $aBookmark['make'] = $sMake;
                        $aBookmark['model'] = '';
                        $aBookmark['current'] = $sBookmark;
                    }

                    if ($sModel != $aBookmark['model'])
                    {
                        $aBookmark['model'] = $sModel;
                        $oCatalog->create_bookmark($sModel, sprintf('parent=%d', $aBookmark['current']));
                        $aVehicle[] = ['make' => $aBookmark['make'], 'model' => $aBookmark['model'], 'page' => $this->aOption['pagination']];
                    }
                }
            }
            
            if ($sModel != $aShift['model1'])
            {
                if ($sRaw >= 69) {
                    $sData = false;
                }
    
                if ($sData)
                {
                    foreach ([1, 2, 7, 8] as $sCol)
                    {
                        switch ($sCol)
                        {
                            case 1:
                            case 7:
                                $sOption = 'colwidth=%s rowheight=%s fittextline={font=%s fontsize=8 fitmethod=auto position={left center}} margin=2 matchbox={fillcolor=%s}';
                                $sOption = sprintf($sOption, $aPoint[sprintf('cellWidth%d', $sCol)], $aPoint['cellHeight'], $this->aOption['font']['arial_bd'], $this->aOption['colors']['back']);
                                break;
    
                            case 2:
                                $sOption = 'colwidth=%s rowheight=%s colspan=5 fittextline={font=%s fontsize=8 fitmethod=auto} ';
                                $sOption = sprintf($sOption, $aPoint[sprintf('cellWidth%d', $sCol)], $aPoint['cellHeight'] * 2, $this->aOption['font']['arial_bd']);
                                break;
                                
                            default:
                                $sOption = 'colwidth=%s rowheight=%s fittextline={font=%s fontsize=8 fitmethod=auto} ';
                                $sOption = sprintf($sOption, $aPoint[sprintf('cellWidth%d', $sCol)], $aPoint['cellHeight'], $this->aOption['font']['arial_bd']);
                                break;
                        }
        
                        $sResult = $oCatalog->addTableCell($sResult, $sCol, $sRow, ($sCol == 1) ? $aShift['model1'] : '', $sOption);
                    }

                    $sModel = $aShift['model1'];
                    if ($aBookmark['model'] != $aShift['model1'])
                    {
                        $aBookmark['model'] = $aShift['model1'];
                        $oCatalog->create_bookmark($aShift['model1'], sprintf('parent=%d', $aBookmark['current']));
                        $aVehicle[] = ['make' => $aBookmark['make'],'model' => $aBookmark['model'], 'page' => $this->aOption['pagination']];
                    }

                    $sRow ++;
                    $sRaw ++;
                }
            }
            
            // 填充单元格
            $sFirst = true;
            $sCell = $sData;
            $sCount = count($aShift['value']);
            while ($sCell)
            {
                $sStart = $sFirst ? 1 : 2;
                $aData = array_shift($aShift['value']);
                for ($sCol = $sStart; $sCol <= 8; $sCol ++)
                {
                    $sOption = '';
                    $sValue = $aData[sprintf('col%d', $sCol - 1)] ?? '';
                    switch ($sCol)
                    {
                        case 1:
                            // 需要计算rowspan
                            $sFirst = false;
                            $sValue = $aShift['model2'];
                            $sOption = 'colwidth=%s rowheight=%s rowspan=%d fittextline={font=%s fontsize=7 fitmethod=auto position={left %s}} margin=2 matchbox={fillcolor=%s}';
                            $sRowspan = (($sCount + $sRaw) > 70) ? (70 - $sRaw) + 1 : $sCount;
                            $sOption = sprintf($sOption, $aPoint['cellWidth1'], $aPoint['cellHeight'] * $sRowspan, $sRowspan, $this->aOption['font']['arial'], ($sRowspan > 1) ? 'top' : 'center', $this->aOption['colors']['back']);
                            break;
                        
                        case 2:
                            $sOption = 'colwidth=%s rowheight=%s fittextline={font=%s fontsize=7 fitmethod=auto position={left center}}';
                            $sOption = sprintf($sOption, $aPoint['cellWidth2'], $aPoint['cellHeight'], $this->aOption['font']['arial']);
                            break;
                        
                        case 3:
                        case 4:
                            $sOption = 'colwidth=%s rowheight=%s fittextline={font=%s fontsize=7 fitmethod=auto position={left center}} marginleft=1';
                            $sOption = sprintf($sOption, $aPoint[sprintf('cellWidth%d', $sCol)], $aPoint['cellHeight'], $this->aOption['font']['arial']);
                            break;
                        
                        case 6:
                        case 5:
                            $sOption = 'colwidth=%s rowheight=%s fittextline={font=%s fontsize=7 fitmethod=auto position={center}} margin=2';
                            $sOption = sprintf($sOption, $aPoint[sprintf('cellWidth%d', $sCol)], $aPoint['cellHeight'], $this->aOption['font']['arial']);
                            break;
                        
                        case 7:
                            $sOption = 'colwidth=%s rowheight=%s fittextline={font=%s fontsize=7 fitmethod=auto position={left center}} matchbox={fillcolor=%s} margin=2';
                            $sOption = sprintf($sOption, $aPoint[sprintf('cellWidth%d', $sCol)], $aPoint['cellHeight'], $this->aOption['font']['arial_bd'], $this->aOption['colors']['back']);
                            break;
                        
                        case 8:
                            $sOption = 'colwidth=%s rowheight=%s fittextline={font=%s fontsize=7 fitmethod=auto position={center}} margin=1';
                            $sOption = sprintf($sOption, $aPoint[sprintf('cellWidth%d', $sCol)], $aPoint['cellHeight'], $this->aOption['font']['arial_bd']);
                            break;
                    }
                    
                    $sResult = $oCatalog->addTableCell($sResult, $sCol, $sRow, trim($sValue), $sOption);
                }
                
                $sRow ++;
                $sRaw ++;
                if (!$aShift['value'] || ($sRaw > 70)) {
                    $sCell = false;
                }
            }
            
            // 页面结束
            if (($sRaw > 70) || !$aValue || !$sData)
            {
                // 如当前弹出数据还有剩余, 插回去
                if ($aShift['value']) {
                    array_unshift($aValue, $aShift);
                }
                
                $sOption = 'header=0 rowheightdefault=auto fitmethod=nofit stroke={
                        {line=frame linewidth=1 strokecolor=%s} 
                        {line=vert1 linewidth=1 strokecolor=%s}
                        {line=vert6 linewidth=1 strokecolor=%s}
                        {line=vert7 linewidth=1 strokecolor=%s}
                        {line=hor1 linewidth=1 strokecolor=%s}
                        {line=other linewidth=0.1}
                    }';
                $sOption = sprintf($sOption, $this->aOption['colors']['line'], $this->aOption['colors']['line'], $this->aOption['colors']['line'], $this->aOption['colors']['line'], $this->aOption['colors']['line']);
                $sResult = $oCatalog->fit_table($sResult, $this->aOption['point']['x1'], $this->aOption['point']['y1'], $this->aOption['point']['x2'], $this->aOption['point']['y2'], $sOption);
                
                $oCatalog = $this->pagination($oCatalog, $this->aOption['pagination']);
                $oCatalog->end_page_ext('');
                $this->aOption['pagination'] ++;
                
                $sRow = 1;
                $sRaw = 1;
                $sMake = '';
                $sModel = '';
                if (!$aValue) {
                    $sWhile = false;
                }
            }
        }
        
        return $sBuffer ? ['vehicle' => $aVehicle, 'pagination' => $this->aOption['pagination'] - 1] : $oCatalog;
    }
    
    /**
     * 水泵车型应用
     *
     * @param PDFlib $oCatalog
     * @param array $aValue  数据
     * @param false $sBuffer 是否只返回车型索引页数据 和 车型应用页页码
     *
     * @example
     * [
     *      'style' => 'modelGuideByWaterPump', // 版式
     *      'value' => [
     *          [
     *              'make' => 'ACURA',
     *              'model1' => 'MDX',
     *              'model2' => '2.7 (130 kW)',
     *              'value' => [
     *                  ['col1' => '1990.12-1994.07','col2' => 'AWD Engine AAR (12.90-.)', 'col3' => '512205',]
     *                  // ...
     *              ]
     *          ],
     *          // ....
     *      ]
     * ]
     *
     * @return array|PDFlib
     */
    public function modelGuideByWaterPump(PDFlib $oCatalog, array $aValue, bool $sBuffer = false)
    {
        $aVehicle = [];
        $aPoint = [
            'cellWidth' => $this->aOption['point']['x2'] - $this->aOption['point']['x1'],
            'cellWidth1' => 158, // 车型列宽度
            'cellWidth2' => 86, // 年份列宽度
            'cellWidth3' => 209, //
            'cellWidth4' => 72, //
            'cellHeight' => 11, // 表格高度

            'car' => sprintf('%s/image/%s/wheelCar.png', $this->aOption['resources'], $this->aOption['color']),
            'year' => sprintf('%s/image/%s/WaterPumpYear.png', $this->aOption['resources'], $this->aOption['color']),
        ];

        // 内容页面
        $sRow = 1;
        $sRaw = 1;
        $sMake = '';
        $sModel = '';
        $sData = true;
        $sWhile = true;

        $sParent = 0;
        $sResult = 0;
        $sRemark = $aValue['remark'] ?? '';
        $aValue = $aValue['value'];
        $aBookmark = ['make' => '', 'model' => '', 'current' => 0];
        $aMatch = [1 => '', 'YEAR', 'BODY STYLE & DRIVE TYPE & ENGINE', $this->aOption['gTitle']];
        while ($sWhile)
        {
            // 页面开始
            if ($sRow == 1)
            {
                $sData = true;
                $sResult = 0;
                $oCatalog->begin_page_ext(0, 0, 'width=a4.width height=a4.height');
                // 分部书签
                if (!$sParent && $sRemark) {
                    $sParent = $oCatalog->create_bookmark($sRemark, sprintf('parent=%d', 0));
                }

                $sHeader = 0;
                for ($sCol = 1; $sCol <= 4; $sCol ++)
                {
                    switch ($sCol)
                    {
                        case 1:
                            $oImage = $oCatalog->loadImage('auto', $aPoint['car'], '');
                            $sOption = 'colwidth=%s rowheight=%s image=%s fitimage={position={center}} fittextline={font=%s fontsize=9 fitmethod=auto} matchbox={fillcolor=%s} margin=1.5';
                            $sOption = sprintf($sOption, $aPoint[sprintf('cellWidth%d', $sCol)], $aPoint['cellHeight'] * 4, $oImage, $this->aOption['font']['arial_bd'], $this->aOption['colors']['back']);
                            break;

                        case 2:
                            $oImage = $oCatalog->loadImage('auto', $aPoint['year'], '');
                            $sOption = 'colwidth=%s rowheight=%s image=%s fitimage={position={center bottom}} fittextline={font=%s fontsize=9 fitmethod=auto fillcolor=%s position={center bottom}} margin=5';
                            $sOption = sprintf($sOption, $aPoint[sprintf('cellWidth%d', $sCol)], $aPoint['cellHeight'] * 4, $oImage, $this->aOption['font']['arial_bd'], $this->aOption['colors']['font']);
                            break;

                        case 4:
                            $sOption = 'colwidth=%s rowheight=%s fittextline={font=%s fontsize=9 fitmethod=auto fillcolor=%s} matchbox={fillcolor=%s} margin=1.5';
                            $sOption = sprintf($sOption, $aPoint[sprintf('cellWidth%d', $sCol)], $aPoint['cellHeight'] * 4, $this->aOption['font']['arial_bd'], $this->aOption['colors']['font'], $this->aOption['colors']['back']);
                            break;

                        default:
                            $sOption = 'colwidth=%s rowheight=%s fittextline={font=%s fontsize=9 fitmethod=auto fillcolor=%s} margin=2';
                            $sOption = sprintf($sOption, $aPoint[sprintf('cellWidth%d', $sCol)], $aPoint['cellHeight'] * 4, $this->aOption['font']['arial_bd'], $this->aOption['colors']['font']);
                            break;
                    }
                    $sHeader = $oCatalog->addTableCell($sHeader, $sCol, $sRow, $aMatch[$sCol], $sOption);
                }
                $sOption = 'header=0 rowheightdefault=auto stroke={{line=other linewidth=1 strokecolor=%s}}';
                $sOption = sprintf($sOption, $this->aOption['colors']['line']);
                $oCatalog->fit_table($sHeader, $this->aOption['point']['x1'], $this->aOption['point']['y2'] - $aPoint['cellHeight'] * 4, $this->aOption['point']['x2'], $this->aOption['point']['y2'], $sOption);

                $sOption = 'rowheight=%s fittextline={font=%s fontsize=7 fillcolor=%s fitmethod=auto} colspan=4';
                $sOption = sprintf($sOption, $aPoint['cellHeight'] * 4, $this->aOption['font']['arial_bd'], $this->aOption['colors']['font']);
                $sResult = $oCatalog->addTableCell($sResult, 1, $sRow, '', $sOption);

                $sRow ++;
                $sRaw = $sRaw + 4;
            }

            // 抽取数据
            $aShift = array_shift($aValue);

            // 车型列
            if ($sMake != $aShift['make'])
            {
                if ($sRaw >= 67) {
                    $sData = false;
                }

                if ($sData)
                {
                    $aCol = [1, 2, 4];
                    foreach ($aCol as $sCol)
                    {
                        switch ($sCol)
                        {
                            case 1:
                                // 解决超出问题
                                $sChild = 0;
                                $sOption = 'colwidth=%s rowheight=%s fittextline={font=%s fontsize=10 fitmethod=auto position={left center}} matchbox={fillcolor=%s} margin=2';
                                $sOption = sprintf($sOption, $aPoint['cellWidth1'], $aPoint['cellHeight'], $this->aOption['font']['arial_bd'], $this->aOption['colors']['back']);
                                $sChild = $oCatalog->addTableCell($sChild, 1, 1, $aShift['make'], $sOption);

                                $sOption = 'colwidth=%s rowheight=%s fittextline={font=%s fontsize=8 fitmethod=auto position={left center}} matchbox={fillcolor=%s} margin=2';
                                $sOption = sprintf($sOption, $aPoint['cellWidth1'], $aPoint['cellHeight'], $this->aOption['font']['arial_bd'], $this->aOption['colors']['back']);
                                $sChild = $oCatalog->addTableCell($sChild, 1, 2, $aShift['model1'], $sOption);

                                $sOption = 'header=0 rowheightdefault=auto stroke={{line=other linewidth=0}}';
                                $oCatalog->fit_table(
                                    $sChild,
                                    $this->aOption['point']['x1'],
                                    $this->aOption['point']['y2'] - ($sRaw + 1) * $aPoint['cellHeight'],
                                    $this->aOption['point']['x1'] + $aPoint['cellWidth1'],
                                    $this->aOption['point']['y2'] - ($sRaw - 1) * $aPoint['cellHeight'],
                                    $sOption
                                );

                                $sOption = 'colwidth=%s rowheight=%s';
                                $sOption = sprintf($sOption, $aPoint['cellWidth1'], $aPoint['cellHeight'] * 2);
                                $sResult = $oCatalog->addTableCell($sResult, $sCol, $sRow, '', $sOption);
                                break;

                            case 4:
                                $sOption = 'colwidth=%s rowheight=%s matchbox={fillcolor=%s}';
                                $sOption = sprintf($sOption, $aPoint['cellWidth4'], $aPoint['cellHeight'] * 2,  $this->aOption['colors']['back']);
                                $sResult = $oCatalog->addTableCell($sResult, $sCol, $sRow, '', $sOption);
                                break;

                            default:
                                $sOption = 'colwidth=%s rowheight=%s colspan=2 margin=2';
                                $sOption = sprintf($sOption, ($aPoint['cellWidth2'] + $aPoint['cellWidth3']), $aPoint['cellHeight'] * 2);
                                $sResult = $oCatalog->addTableCell($sResult, $sCol, $sRow, '', $sOption);
                                break;
                        }
                    }

                    $sRow ++;
                    $sRaw = $sRaw + 2;
                    $sMake = $aShift['make'];
                    $sModel = $aShift['model1'];

                    if ($aBookmark['make'] != $aShift['make'])
                    {
                        $sBookmark = $oCatalog->create_bookmark($aShift['make'], sprintf('parent=%d', $sParent));
                        $aBookmark['make'] = $aShift['make'];
                        $aBookmark['model'] = '';
                        $aBookmark['current'] = $sBookmark;
                    }

                    if ($aBookmark['model'] != $aShift['model1'])
                    {
                        $aBookmark['model'] = $aShift['model1'];
                        $oCatalog->create_bookmark($aShift['model1'], sprintf('parent=%d', $aBookmark['current']));
                        $aVehicle[] = ['make' => $aBookmark['make'],'model' => $aBookmark['model'], 'page' => $this->aOption['pagination']];
                    }
                }
            }

            if ($aShift['model1'] != $sModel)
            {
                if ($sRaw >= 69) {
                    $sData = false;
                }

                if ($sData)
                {
                    for ($sCol = 1; $sCol <= 4; $sCol ++)
                    {
                        if ($sCol == 3) {
                            continue;
                        }

                        switch ($sCol)
                        {
                            case 2:
                                $sOption = 'colwidth=%s rowheight=%s  margin=2 colspan=2';
                                $sOption = sprintf($sOption, ($aPoint['cellWidth2'] + $aPoint['cellWidth3']), $aPoint['cellHeight']);
                                $sResult = $oCatalog->addTableCell($sResult, $sCol, $sRow, '', $sOption);
                                break;

                            default:
                                $sColor = (($sCol == 1) || ($sCol == 4)) ? $this->aOption['colors']['back']: $this->aOption['colors']['white'];
                                $sOption = 'colwidth=%s rowheight=%s fittextline={font=%s fontsize=8 fitmethod=auto position={left center}} margin=2 matchbox={fillcolor=%s}';
                                $sOption = sprintf($sOption, $aPoint[sprintf('cellWidth%d', $sCol)], $aPoint['cellHeight'], $this->aOption['font']['arial_bd'], $sColor);
                                $sResult = $oCatalog->addTableCell($sResult, $sCol, $sRow, ($sCol == 1) ? $aShift['model1'] : '', $sOption);
                                break;
                        }
                    }

                    $sModel = $aShift['model1'];
                    if ($aBookmark['model'] != $aShift['model1'])
                    {
                        $aBookmark['model'] = $aShift['model1'];
                        $oCatalog->create_bookmark($aShift['model1'], sprintf('parent=%d', $aBookmark['current']));
                        $aVehicle[] = ['make' => $aBookmark['make'],'model' => $aBookmark['model'], 'page' => $this->aOption['pagination']];
                    }

                    $sRow ++;
                    $sRaw ++;
                }
            }

            // 填充单元格
            $sFirst = true;
            $sCell = $sData;
            $sCount = count($aShift['value']);
            while ($sCell)
            {
                $sStart = $sFirst ? 1 : 2;
                $aData = array_shift($aShift['value']);
                for ($sCol = $sStart; $sCol <= 4; $sCol ++)
                {
                    $sValue = '';
                    $sOption = '';
                    switch ($sCol)
                    {
                        case 1:
                            // 需要计算rowspan
                            $sFirst = false;
                            $sValue = $aShift['model2'];
                            $sOption = 'colwidth=%s rowheight=%s rowspan=%d fittextline={font=%s fontsize=7 fitmethod=auto position={left top}} margin=2 matchbox={fillcolor=%s}';
                            $sRowspan = (($sCount + $sRaw) > 70) ? (70 - $sRaw) + 1 : $sCount;
                            if ($sRowspan <= 0) {
                                dd($sRowspan);
                            }
                            $sOption = sprintf($sOption, $aPoint[sprintf('cellWidth%d', $sCol)], $aPoint['cellHeight'] * $sRowspan, $sRowspan, $this->aOption['font']['arial'], $this->aOption['colors']['back']);
                            break;

                        case 2:
                            $sValue = $aData['col1'];
                            $sOption = 'colwidth=%s rowheight=%s fittextline={font=%s fontsize=7 fitmethod=auto position={left center}} margin=2';
                            $sOption = sprintf($sOption, $aPoint[sprintf('cellWidth%d', $sCol)], $aPoint['cellHeight'], $this->aOption['font']['arial']);
                            break;

                        case 3:
                            $sValue = $aData['col2'];
                            $sOption = 'colwidth=%s rowheight=%s fittextline={font=%s fontsize=7 fitmethod=auto position={left center}} margin=2';
                            $sOption = sprintf($sOption, $aPoint[sprintf('cellWidth%d', $sCol)], $aPoint['cellHeight'], $this->aOption['font']['arial']);
                            break;

                        case 4:
                            $sValue = $aData['col3'];
                            $sOption = 'colwidth=%s rowheight=%s fittextline={font=%s fontsize=7 fitmethod=auto position={left center}} margin=2 matchbox={fillcolor=%s}';
                            $sOption = sprintf($sOption, $aPoint[sprintf('cellWidth%d', $sCol)], $aPoint['cellHeight'], $this->aOption['font']['arial_bd'], $this->aOption['colors']['back']);
                            break;
                    }

                    $sResult = $oCatalog->addTableCell($sResult, $sCol, $sRow, $sValue, $sOption);
                }

                $sRow ++;
                $sRaw ++;
                if (!$aShift['value'] || ($sRaw > 70)) {
                    $sCell = false;
                }
            }

            // 页面结束
            if (($sRaw >= 70) || !$aValue || !$sData)
            {
                // 如当前弹出数据还有剩余, 插回去
                if ($aShift['value']) {
                    array_unshift($aValue, $aShift);
                }

                $sOption = 'header=0 rowheightdefault=auto stroke={
                        {line=frame linewidth=1 strokecolor=%s} 
                        {line=vert1 linewidth=1 strokecolor=%s}
                        {line=vert3 linewidth=1 strokecolor=%s}
                        {line=hor1 linewidth=1 strokecolor=%s}
                        {line=other linewidth=0.5 strokecolor=%s}
                    }';
                $sOption = sprintf($sOption, $this->aOption['colors']['line'], $this->aOption['colors']['line'], $this->aOption['colors']['line'], $this->aOption['colors']['line'], $this->aOption['colors']['black']);
                $sResult = $oCatalog->fit_table($sResult, $this->aOption['point']['x1'], $this->aOption['point']['y1'], $this->aOption['point']['x2'], $this->aOption['point']['y2'], $sOption);

                $oCatalog = $this->pagination($oCatalog, $this->aOption['pagination']);
                $oCatalog->end_page_ext('');

                $sRow = 1;
                $sRaw = 1;
                $sMake = '';
                $sModel = '';
                $this->aOption['pagination'] ++;
                if (!$aValue) {
                    $sWhile = false;
                }
            }
        }
        return $sBuffer ? ['vehicle' => $aVehicle, 'pagination' => $this->aOption['pagination'] - 1] : $oCatalog;
    }
    
    /**
     * 减振器车型应用
     *
     * @param PDFlib $oCatalog
     * @param array $aValue  数据
     * @param false $sBuffer 是否只返回车型索引页数据 和 车型应用页页码
     *
     * @example
     * [
     *      'style' => 'modelGuideByShockAbsorber', // 版式
     *      'value' => [
     *          [
     *              'make' => 'ACURA',
     *              'model1' => 'MDX',
     *              'model2' => '1966-1970',
     *              'remark' => "Quattro ALL (4A, C4) \nWith Sport sus.\nExc. S4",
     *              'value' => [
     *                  ['col1' => 'L', 'col2' => '31201740', 'col3' => '32201740', 'col4' => '20.png', 'col5' => 'L', 'col6' => '31201740', 'col7' => '32201740', 'col8' => '21.png'],
     *                  ['col1' => 'R', 'col2' => '31201740', 'col3' => '32201740', 'col4' => '22.png', 'col5' => 'R', 'col6' => '31201740', 'col7' => '32201740', 'col8' => '23.png'],
     *              ]
     *          ],
     *          // ....
     *      ]
     * ]
     *
     * @return array|PDFlib
     */
    public function modelGuideByShockAbsorber(PDFlib $oCatalog, array $aValue, bool $sBuffer = false)
    {
        $aPoint = array_merge($this->aOption['point'], [
            'cellWidth' => $this->aOption['point']['x2'] - $this->aOption['point']['x1'],
            'cellWidth1' => 90,
            'cellWidth2' => 163,
            'cellWidthSmall1' => 15,
            'cellWidthSmall2' => 51,
            'cellWidthSmall3' => 19,
            'cellHeight' => 10,

            'car3' => sprintf('%s/image/%s/shockAbsorberCar1.png', $this->aOption['resources'], $this->aOption['color']),
            'car4' => sprintf('%s/image/%s/shockAbsorberCar2.png', $this->aOption['resources'], $this->aOption['color']),
            'year' => sprintf('%s/image/%s/WaterPumpYear.png', $this->aOption['resources'], $this->aOption['color']),
            'tool' => sprintf('%s/image/%s/shockAbsorberTool.png', $this->aOption['resources'], $this->aOption['color']),
        ]);
        $aPoint['cellWidthGsp'] = $aPoint['x1'] + $aPoint['cellWidth1'] + $aPoint['cellWidth2'];
        $aPoint['cellWidthOther'] = ($aPoint['cellWidth'] - $aPoint['cellWidth1'] - $aPoint['cellWidth2']) / 2;

        // 内容页面
        $sRow = 1;
        $sRaw = 1;
        $sMake = '';
        $sData = true;
        $sModel = '';
        $sResult = 0;
        $sParent = 0;
        $sWhile = true;
        $aVehicle = [];
        $sRemark = $aValue['remark'] ?? '';
        $aValue = $aValue['value'];
        $aBookmark = ['make' => '', 'model' => '', 'current' => 0];
        while ($sWhile)
        {
            if ($sRaw === 1)
            {
                $sMake = '';
                $sData = true;
                $sModel = '';
                $sHeader = 0;
                $sResult = 0;
                $oCatalog->begin_page_ext(0, 0, 'width=a4.width height=a4.height');

                // 分部书签
                if (!$sParent && $sRemark) {
                    $sParent = $oCatalog->create_bookmark($sRemark, sprintf('parent=%d', 0));
                }

                // 解决头部划线问题
                for ($sCol = 1; $sCol <= 4; $sCol ++)
                {
                    switch ($sCol)
                    {
                        case 1:
                            $sValue = 'APPLICATION';
                            $sOption = 'colwidth=%s rowheight=%s fittextline={font=%s fontsize=9 fillcolor=%s position={center}} margin=3';
                            $sOption = sprintf($sOption, $aPoint[sprintf('cellWidth%d', $sCol)], $aPoint['cellHeight'] * 4, $this->aOption['font']['arial_bd'], $this->aOption['colors']['font']);
                            break;

                        case 3:
                        case 4:
                            $sCell = 0;
                            for ($sSmall = 1; $sSmall <= 2; $sSmall ++)
                            {
                                $sOption = 'colwidth=%s rowheight=%s fittextline={font=%s fontsize=9 fitmethod=auto fillcolor=%s}';
                                $sOption = sprintf($sOption, $aPoint['cellWidthSmall1'], $aPoint['cellHeight'] * 2, $this->aOption['font']['arial_bd'], $this->aOption['colors']['font']);
                                $sCell = $oCatalog->addTableCell($sCell, 1, $sSmall, ($sSmall == 1) ? 'L' : 'R', $sOption);
                            }
                            $sOption = 'header=0 rowheightdefault=auto stroke={{line=frame linewidth=0}}';
                            $oCatalog->fit_table($sCell,
                                $aPoint['cellWidthGsp'] + ($sCol - 3) * $aPoint['cellWidthOther'],
                                $aPoint['y2'] - 4 * $aPoint['cellHeight'],
                                $aPoint['cellWidthGsp'] + ($sCol - 3) * $aPoint['cellWidthOther'] + $aPoint['cellWidthSmall1'],
                                $aPoint['y2'],
                                $sOption
                            );

                            $sCell = 0;
                            $aTable = [
                                1 => [1 => [2, 2, 2, '', $aPoint[sprintf('car%d', $sCol)]]],
                                2 => [1 => [2, 2, 1, $this->aOption['gTitle']]],
                                3 => [1 => [1, 1, 1, 'OIL'], 2 => [1, 1, 1, 'GAS']]
                            ];
                            foreach ($aTable as $sKK1 => $aVV1)
                            {
                                foreach ($aVV1 as $sKK2 => $aVV2)
                                {
                                    if ($aVV2[4])
                                    {
                                        $oImage = $oCatalog->loadImage('auto', $aVV2[4], '');
                                        $sOption = 'colwidth=%s rowheight=%s image=%s fitimage={position={center}} margin=2 colspan=%d';
                                        $sOption = sprintf($sOption, $aPoint['cellWidthSmall2'] * $aVV2[1], $aPoint['cellHeight'] * $aVV2[2], $oImage, $aVV2[0]);
                                    } else
                                    {
                                        $sOption = 'colwidth=%s rowheight=%s fittextline={font=%s fontsize=9 fitmethod=auto fillcolor=%s} colspan=%d';
                                        $sOption = sprintf($sOption, $aPoint['cellWidthSmall2'] * $aVV2[1], $aPoint['cellHeight'] * $aVV2[2], $this->aOption['font']['arial_bd'], $this->aOption['colors']['font'], $aVV2[0]);
                                    }
                                    $sCell = $oCatalog->addTableCell($sCell, $sKK2, $sKK1, $aVV2[3], $sOption);
                                }
                            }
                            $sOption = 'header=0 rowheightdefault=auto stroke={{line=other linewidth=0.1}}';
                            $oCatalog->fit_table($sCell,
                                $aPoint['cellWidthGsp'] + ($sCol - 3) * $aPoint['cellWidthOther'] + $aPoint['cellWidthSmall1'],
                                $aPoint['y2'] - 4 * $aPoint['cellHeight'],
                                $aPoint['cellWidthGsp'] + ($sCol - 3) * $aPoint['cellWidthOther'] + $aPoint['cellWidthSmall1'] + $aPoint['cellWidthSmall2'] * 2,
                                $aPoint['y2'],
                                $sOption
                            );

                            $sCell = 0;
                            $oImage = $oCatalog->loadImage('auto', $aPoint['tool'], '');
                            $sOption = 'colwidth=%s rowheight=%s image=%s fitimage={position={center}} margin=2';
                            $sOption = sprintf($sOption, $aPoint['cellWidthSmall3'], $aPoint['cellHeight'] * 4, $oImage);
                            $sCell = $oCatalog->addTableCell($sCell, 1, 1, '', $sOption);

                            $sOption = 'header=0 rowheightdefault=auto stroke={{line=frame linewidth=0.1}}';
                            $oCatalog->fit_table($sCell,
                                $aPoint['x2'] - ($sCol - 3) * $aPoint['cellWidthOther'] - $aPoint['cellWidthSmall3'],
                                $aPoint['y2'] - 4 * $aPoint['cellHeight'],
                                $aPoint['x2'] - ($sCol - 3) * $aPoint['cellWidthOther'],
                                $aPoint['y2'],
                                $sOption
                            );

                            $sValue = '';
                            $sOption = 'colwidth=%s rowheight=%s fittextline={font=%s fontsize=9 fitmethod=auto}';
                            $sOption = sprintf($sOption, $aPoint['cellWidthOther'], $aPoint['cellHeight'] * 4, $this->aOption['font']['arial_bd']);
                            break;

                        default:
                            $sValue = 'REMARK';
                            $sOption = 'colwidth=%s rowheight=%s fittextline={font=%s fontsize=9 fitmethod=auto fillcolor=%s position={center}}';
                            $sOption = sprintf($sOption, $aPoint[sprintf('cellWidth%d', $sCol)], $aPoint['cellHeight'] * 4, $this->aOption['font']['arial_bd'], $this->aOption['colors']['font']);
                            break;
                    }

                    $sHeader = $oCatalog->addTableCell($sHeader, $sCol, 1, $sValue, $sOption);
                }

                $sOption = 'header=0 rowheightdefault=auto stroke={
                        {line=frame linewidth=1 strokecolor=%s} 
                        {line=vert2 linewidth=1 strokecolor=%s} 
                        {line=vert3 linewidth=1 strokecolor=%s} 
                        {line=other linewidth=0.1}
                    }';
                $sOption = sprintf($sOption, $this->aOption['colors']['line'], $this->aOption['colors']['line'], $this->aOption['colors']['line']);
                $oCatalog->fit_table($sHeader, $aPoint['x1'], $aPoint['y2'] - $aPoint['cellHeight'] * 4, $aPoint['x2'], $aPoint['y2'], $sOption);
                $sRaw = $sRaw + 4;
            }
            $aShift = array_shift($aValue);

            // 品牌列
            if ($sMake != $aShift['make'])
            {
                if (($sRaw + 5) > 77) {
                    $sData = false;
                }

                if ($sData)
                {
                    // 解决超出问题
                    $sChild = 0;
                    $sOption = 'colwidth=%s rowheight=%s fittextline={font=%s fontsize=10 fitmethod=auto position={bottom center}} margin=2';
                    $sOption = sprintf($sOption, $aPoint['cellWidth'], $aPoint['cellHeight'], $this->aOption['font']['arial_bd']);
                    $sChild = $oCatalog->addTableCell($sChild, 1, 1, $aShift['make'], $sOption);

                    $sOption = 'colwidth=%s rowheight=%s fittextline={font=%s fontsize=8 fitmethod=auto position={left center}} margin=2';
                    $sOption = sprintf($sOption, $aPoint['cellWidth'], $aPoint['cellHeight'], $this->aOption['font']['arial_bd']);
                    $sChild = $oCatalog->addTableCell($sChild, 1, 2, $aShift['model1'], $sOption);

                    $sOption = 'header=0 rowheightdefault=auto stroke={{line=other linewidth=0}}';
                    $oCatalog->fit_table(
                        $sChild,
                        $this->aOption['point']['x1'],
                        $this->aOption['point']['y2'] - ($sRaw + 1) * $aPoint['cellHeight'],
                        $this->aOption['point']['x2'],
                        $this->aOption['point']['y2'] - ($sRaw - 1) * $aPoint['cellHeight'],
                        $sOption
                    );

                    $sOption = 'colwidth=%s rowheight=%s colspan=4';
                    $sOption = sprintf($sOption, $aPoint['cellWidth'], $aPoint['cellHeight'] * 2);
                    $sResult = $oCatalog->addTableCell($sResult, 1, $sRow, '', $sOption);

                    $sRow ++;
                    $sRaw = $sRaw + 2;
                    $sMake = $aShift['make'];
                    $sModel = $aShift['model1'];
                    if ($sMake != $aBookmark['make'])
                    {
                        $sBookmark = $oCatalog->create_bookmark($aShift['make'], sprintf('parent=%d', $sParent));
                        $aBookmark = ['make' => $aShift['make'], 'model' => '', 'current' => $sBookmark];
                    }

                    if ($sModel != $aBookmark['model'])
                    {
                        $aBookmark['model'] = $sModel;
                        $oCatalog->create_bookmark($sModel, sprintf('parent=%d', $aBookmark['current']));
                        $aVehicle[] = ['make' => $aBookmark['make'], 'model' => $aBookmark['model'], 'page' => $this->aOption['pagination']];
                    }
                }
            }

            // 车型列
            if (($sMake == $aShift['make']) && ($sModel != $aShift['model1']))
            {
                if (($sRaw + 4) > 77) {
                    $sData = false;
                }

                if ($sData)
                {
                    $sOption = 'colwidth=%s rowheight=%s fittextline={font=%s fitmethod=auto fontsize=8 position={left center}} colspan=4 marginleft=2';
                    $sOption = sprintf($sOption, $aPoint['cellWidth'], $aPoint['cellHeight'], $this->aOption['font']['arial_bd']);
                    $sResult = $oCatalog->addTableCell($sResult, 1, $sRow, $aShift['model1'] , $sOption);

                    $sModel = $aShift['model1'];
                    if ($aShift['model1'] != $aBookmark['model'])
                    {
                        $aBookmark['model'] = $aShift['model1'];
                        $oCatalog->create_bookmark($aShift['model1'], sprintf('parent=%d', $aBookmark['current']));
                        $aVehicle[] = ['make' => $aBookmark['make'],'model' => $aBookmark['model'], 'page' => $this->aOption['pagination']];
                    }
                    $sRow ++;
                    $sRaw ++;
                }
            }

            // 号码格子
            if (($sRaw + 3) > 77) {
                $sData = false;
            }
            if ($sData)
            {
                $sCell = 0;
                for ($sRun = 1; $sRun <= 2; $sRun ++)
                {
                    for ($sCol = 1; $sCol <= 8; $sCol ++)
                    {
                        $sValue = $aShift['value'][$sRun - 1][sprintf('col%d', $sCol)] ?? '';
                        switch ($sCol)
                        {
                            case 1:
                            case 5:
                                $sOption = 'colwidth=%s rowheight=%s fittextline={font=%s fontsize=8 fitmethod=auto position={center}} margin=3';
                                $sOption = sprintf($sOption, $aPoint['cellWidthSmall1'], $aPoint['cellHeight'] * 2, $this->aOption['font']['arial_bd']);
                                break;

                            case 4:
                            case 8:
                                $oImage = '';
                                if (pathinfo($sValue, PATHINFO_EXTENSION))
                                {
                                    $sImage = !is_file($sValue)
                                        ? sprintf('%s/image/tools/%s', $this->aOption['resources'], $sValue)
                                        : $sValue;

                                    if (is_file($sImage))
                                    {
                                        $oImage = $oCatalog->loadImage('auto', $sImage, '');
                                        $oImage = sprintf('image=%s', $oImage);
                                    } else
                                    {
                                        dd($sImage, $sValue, 'no image');
                                    }
                                }
                                $sOption = 'colwidth=%s rowheight=%s %s fitimage={position={center}} margin=3';
                                $sOption = sprintf($sOption, $aPoint['cellWidthSmall3'], $aPoint['cellHeight'] * 2, $oImage);
                                $sValue = '';
                                break;

                            default:
                                $sColor = (($sCol % 2) === 1) ? $this->aOption['colors']['back'] : $this->aOption['colors']['white'];
                                $sOption = 'colwidth=%s rowheight=%s fittextline={font=%s fontsize=8 fitmethod=auto position={center}} matchbox={fillcolor=%s} margin=3';
                                $sOption = sprintf($sOption, $aPoint['cellWidthSmall2'], $aPoint['cellHeight'] * 2, $this->aOption['font']['arial_bd'], $sColor);
                                break;
                        }
                        $sCell = $oCatalog->addTableCell($sCell, $sCol, $sRun, $sValue, $sOption);
                    }
                }
                $sOption = 'header=0 rowheightdefault=auto stroke={{line=frame linewidth=0} {line=vertother linewidth=0.1}}';
                $oCatalog->fit_table($sCell, $aPoint['cellWidthGsp'], $aPoint['y2'] - ($sRaw + 3) * $aPoint['cellHeight'], $aPoint['x2'], $aPoint['y2'] - ($sRaw - 1) * $aPoint['cellHeight'], $sOption);

                // 填充单元格
                for ($sCol = 1; $sCol <= 4; $sCol ++)
                {
                    switch ($sCol)
                    {
                        case 1:
                            $sChild = 0;
                            $sValue = $aShift['model2'];
                            $sOption = sprintf('fontname=font/arial encoding=unicode fontsize=8',);
                            $sChild = $oCatalog->add_textflow($sChild, $sValue, $sOption);
                            $sOption = 'colwidth=%s rowheight=%s fittextline={font=%s fontsize=8 fitmethod=auto position={left top}} textflow=%s fittextflow={verticalalign=top} marginleft=3 margintop=1';
                            $sOption = sprintf($sOption, $aPoint['cellWidth1'], $aPoint['cellHeight'] * 4, $this->aOption['font']['arial'], $sChild);
                            break;

                        case 2:
                            $sFont = 7;
                            //$sValue = trim(str_replace([',', ';'], [', ', '; '], $aShift['remark']));
                            $sValue = trim($aShift['remark']);
                            $sLen = mb_strlen($sValue);
                            if ($sLen > 150) {
                                $sFont = 7;
                            }
                            if ($sLen > 200) {
                                $sFont = 6;
                            }
                            if ($sLen > 300) {
                                $sFont = 5;
                            }
                            # alignment=justify
                            # alignment=left
                            $sOption = sprintf('fontname=font/arial encoding=unicode fontsize=%d alignment=justify charref=true avoidemptybegin=true', $sFont);
                            $sChild = $oCatalog->create_textflow(htmlspecialchars($sValue, ENT_QUOTES), $sOption);

                            $img_llx = $aPoint['x1'] + $aPoint['cellWidth1'] + 2;
                            $img_lly = $aPoint['y2'] - $aPoint['cellHeight'] * (3 + $sRaw) + 2;

                            $oCatalog->fit_textflow($sChild, $img_llx, $img_lly, $img_llx + $aPoint['cellWidth2'] - 4, $img_lly + 4 * $aPoint['cellHeight'] - 4, "");
                            $oCatalog->delete_textflow($sChild);

                            $sOption = 'colwidth=%s rowheight=%s fittextline={font=%s fontsize=8}';
                            $sOption = sprintf($sOption, $aPoint[sprintf('cellWidth%d', $sCol)], $aPoint['cellHeight'] * 4, $this->aOption['font']['arial']);
                            break;

                        default:
                            // 划号码格子
                            $sOption = 'colwidth=%s rowheight=%s fittextline={font=%s fontsize=8 fitmethod=auto position={center}} margin=3';
                            $sOption = sprintf($sOption, $aPoint['cellWidthOther'], $aPoint['cellHeight'] * 4, $this->aOption['font']['arial']);
                            break;
                    }
                    $sResult = $oCatalog->addTableCell($sResult, $sCol, $sRow, '' , $sOption);
                }
                $sRow ++;
                $sRaw = $sRaw + 4;
            } else {
                array_unshift($aValue, $aShift);
            }

            // 结尾
            if (!$sData || !$aValue)
            {
                $sOption = 'header=0 rowheightdefault=auto stroke={
                        {line=frame linewidth=1 strokecolor=%s} 
                        {line=vert2 linewidth=1 strokecolor=%s} 
                        {line=vert3 linewidth=1 strokecolor=%s} 
                        {line=other linewidth=0.1}
                    }';
                $sOption = sprintf($sOption, $this->aOption['colors']['line'], $this->aOption['colors']['line'], $this->aOption['colors']['line']);
                $oCatalog->fit_table($sResult, $aPoint['x1'], $aPoint['y1'], $aPoint['x2'], $aPoint['y2'] - $aPoint['cellHeight'] * 4, $sOption);

                $oCatalog = $this->pagination($oCatalog, $this->aOption['pagination']);
                $oCatalog->end_page_ext('');
                $this->aOption['pagination'] ++;

                $sRow = 1;
                $sRaw = 1;
                if (!$aValue) {
                    $sWhile = false;
                }
            }
        }

        return $sBuffer ? ['vehicle' => $aVehicle, 'pagination' => $this->aOption['pagination'] - 1] : $oCatalog;
    }

    /**
     * 传动轴车型应用
     *
     * @param PDFlib $oCatalog
     * @param array $aValue  数据
     * @param false $sBuffer 是否只返回车型索引页数据 和 车型应用页页码
     *
     * @example
     * [
     *      'style' => 'modelGuideByPropShaft', // 版式
     *      'value' => [
     *          [
     *              'make' => 'ACURA',
     *              'model1' => 'MDX',
     *              'model2' => '1966-1970',
     *              'remark' => "Quattro ALL (4A, C4) \nWith Sport sus.\nExc. S4",
     *              'value' => [
     *                  ['col1'=> '1990.12-', 'col2' => '1994.07', 'col3'=> 'AT/MT', 'col4' => 'L/R', 'col5' => 'F', 'col6' => 'Engine AR 34103 (09.98-.)', 'col7' => 'Date from:1986.04', 'col8' => '802015', 'col9' => 'Outer Joint', 'col10' => '√', 'col11' => 27, 'col12' => 28, 'col13' => 59, 'col14' => 84, 'col15' => 61.5, 'col16' => 'M'],
     *                  // ...
     *              ]
     *          ],
     *          // ....
     *      ]
     * ]
     *
     * @return array|PDFlib
     */
    public function modelGuideByPropShaft(PDFlib $oCatalog, array $aValue, bool $sBuffer = false)
    {
        $aVehicle = [];
        $aPoint = [
            'cellWidth' => $this->aOption['point']['x2'] - $this->aOption['point']['x1'],
            'cellWidth1' => 105, // 车型列宽度
            'cellWidth2' => 50, // 年份列宽度
            'cellWidth3' => 28, // AT/MT
            'cellWidth4' => 15, // FR
            'cellWidth5' => 15, // LR
            'cellWidth6' => 72, // DRIVE TYPE & ENGINE
            'cellWidth7' => 70, // REMARKS
            'cellWidth8' => 31, // GSP
            'cellWidth9' => 34, // product
            
            'cellWidth10' => 15, // abs
            'cellWidth11' => 15, // A
            'cellWidth12' => 15, // B
            'cellWidth13' => 15, // C
            'cellWidth14' => 15, // H
            'cellWidth15' => 15, // L
            'cellWidth16' => 15, // P
            
            'cellHeight' => 11, // 表格高度
            'cellHeightHeader' => 16.5,
            
            'pic1' => sprintf('%s/image/%s/wheelCar.png', $this->aOption['resources'], $this->aOption['color']),
            'pic2' => sprintf('%s/image/%s/WaterPumpYear.png', $this->aOption['resources'], $this->aOption['color']),
            'pic9' => sprintf('%s/image/%s/8.png', $this->aOption['resources'], $this->aOption['color']),
            'pic10' => sprintf('%s/image/%s/abs.png', $this->aOption['resources'], $this->aOption['color']),
        ];

        $aHeader = [
            1 => [
                1 => [2, 1, '', 9],
                2 => [2, 1, 'YEAR', 9],
                3 => [2, 1, 'TRANSM.', 5],
                4 => [2, 1, 'F/R', 6],
                5 => [2, 1, 'L/R', 6],
                6 => [2, 1, 'BODY STYLE & DRIVE TYPE & ENGINE', 6],
                7 => [2, 1, 'REMARKS', 9],
                8 => [2, 1, $this->aOption['gTitle'], 7],
                9 => [2, 1, 'PRODUCT', 6],
                10 => [2, 1, 'ABS', 5],
                11 => [1, 6, 'Technical Specifications', 7],
            ],
            2 => [
                11 => [1, 1, 'A', 9],
                12 => [1, 1, 'B', 9],
                13 => [1, 1, 'C', 9],
                14 => [1, 1, 'H', 9],
                15 => [1, 1, 'L', 9],
                16 => [1, 1, 'P', 9],
            ]
        ];
        
        // 内容页面
        $sRow = 1;
        $sRaw = 1;
        $sMake = '';
        $sModel = '';
        $sData = true;
        $sWhile = true;
        $sParent = 0;
        $sResult = 0;
        $aCenter = [2, 6, 7, 9];
        $sRemark = $aValue['remark'] ?? '';
        $aValue = $aValue['value'];
        $aBookmark = ['make' => '', 'model' => '', 'current' => 0];
        while ($sWhile)
        {
            // 页面开始
            if ($sRow == 1)
            {
                $sData = true;
                $sResult = 0;
                $oCatalog->begin_page_ext(0, 0, 'width=a4.width height=a4.height');
                
                // 分部书签
                if (!$sParent && $sRemark) {
                    $sParent = $oCatalog->create_bookmark($sRemark, sprintf('parent=%d', 0));
                }
                
                foreach ($aHeader as $sRow => $aVal)
                {
                    foreach ($aVal as $sCol => $aCol)
                    {
                        switch ($sCol)
                        {
                            case 1:
                                $oImage = $oCatalog->loadImage('auto', $aPoint[sprintf('pic%d', $sCol)], '');
                                $sOption = 'colwidth=%s rowheight=%s image=%s fitimage={position={center}} matchbox={fillcolor=%s} rowspan=%d colspan=%d margin=1.5';
                                $sOption = sprintf($sOption, $aPoint[sprintf('cellWidth%d', $sCol)], $aPoint['cellHeightHeader'] * $aCol[0], $oImage, $this->aOption['colors']['back'], $aCol[0], $aCol[1]);
                                break;
                            
                            case 2:
                            case 9:
                            case 10:
                                $oImage = $oCatalog->loadImage('auto', $aPoint[sprintf('pic%d', $sCol)], '');
                                $sOption = 'colwidth=%s rowheight=%s image=%s fitimage={position={center bottom}} fittextline={font=%s fontsize=7 fillcolor=%s fitmethod=auto position={center bottom}} rowspan=%d colspan=%d margin=1.5';
                                $sOption = sprintf($sOption, $aPoint[sprintf('cellWidth%d', $sCol)], $aPoint['cellHeightHeader'] * $aCol[0], $oImage, $this->aOption['font']['arial_bd'],$this->aOption['colors']['font'], $aCol[0], $aCol[1]);
                                break;
                            
                            default:
                                $sColor = ($sCol == 8) ? $this->aOption['colors']['back'] : $this->aOption['colors']['white'];
                                $sOption = 'colwidth=%s rowheight=%s fittextline={font=%s fontsize=%d fitmethod=auto fillcolor=%s} matchbox={fillcolor=%s} rowspan=%d colspan=%d margin=1.5';
                                $sOption = sprintf($sOption, $aPoint[sprintf('cellWidth%d', $sCol)], $aPoint['cellHeightHeader'] * $aCol[0], $this->aOption['font']['arial_bd'], $aCol[3], $this->aOption['colors']['font'], $sColor, $aCol[0], $aCol[1]);
                                break;
                        }
                        $sResult = $oCatalog->addTableCell($sResult, $sCol, $sRow, $aCol[2], $sOption);
                    }
                }
                
                $sRow ++;
                $sRaw = $sRaw + 3;
            }
            $aShift = array_shift($aValue);

            // 车型列
            if ($sMake != $aShift['make'])
            {
                if ($sRaw >= 67) {
                    $sData = false;
                }
    
                if ($sData)
                {
                    foreach ([1, 2, 8, 9] as $sCol)
                    {
                        switch ($sCol)
                        {
                            case 1:
                                $sChild = 0;
                                $sOption = 'colwidth=%s rowheight=%s fittextline={font=%s fontsize=10 fitmethod=auto position={left center}} matchbox={fillcolor=%s} margin=1.5';
                                $sOption = sprintf($sOption, $aPoint['cellWidth1'], $aPoint['cellHeight'], $this->aOption['font']['arial_bd'], $this->aOption['colors']['back']);
                                $sChild = $oCatalog->addTableCell($sChild, 1, 1, $aShift['make'], $sOption);
    
                                $sOption = 'colwidth=%s rowheight=%s fittextline={font=%s fontsize=8 fitmethod=auto position={left center}} matchbox={fillcolor=%s} margin=2';
                                $sOption = sprintf($sOption, $aPoint['cellWidth1'], $aPoint['cellHeight'], $this->aOption['font']['arial_bd'], $this->aOption['colors']['back']);
                                $sChild = $oCatalog->addTableCell($sChild, 1, 2, $aShift['model1'], $sOption);
    
                                $sOption = 'header=0 rowheightdefault=auto stroke={{line=other linewidth=0}}';
                                $sChild = $oCatalog->fit_table(
                                    $sChild,
                                    $this->aOption['point']['x1'],
                                    $this->aOption['point']['y2'] - ($sRaw + 1) * $aPoint['cellHeight'],
                                    $this->aOption['point']['x1'] + $aPoint['cellWidth1'],
                                    $this->aOption['point']['y2'] - ($sRaw - 1) * $aPoint['cellHeight'],
                                    $sOption
                                );
    
                                $sOption = 'colwidth=%s rowheight=%s';
                                $sOption = sprintf($sOption, $aPoint[sprintf('cellWidth%d', $sCol)], $aPoint['cellHeight'] * 2);
                                break;
            
                            case 2:
                            case 9:
                                $sOption = 'rowheight=%s fittextline={font=%s fontsize=8 fitmethod=auto} colspan=%d';
                                $sOption = sprintf($sOption, $aPoint['cellHeight'] * 2, $this->aOption['font']['arial_bd'], ($sCol == 2) ? 6 : 8);
                                break;
            
                            case 8:
                                $sOption = 'colwidth=%s rowheight=%s fittextline={font=%s fontsize=14 fitmethod=auto position={left center}} margin=2 matchbox={fillcolor=%s}';
                                $sOption = sprintf($sOption, $aPoint[sprintf('cellWidth%d', $sCol)], $aPoint['cellHeight'] * 2, $this->aOption['font']['arial_bd'], $this->aOption['colors']['back']);
                                break;
            
                            default: $sOption = ''; break;
                        }
        
                        $sResult = $oCatalog->addTableCell($sResult, $sCol, $sRow, '', $sOption);
                    }
    
                    $sRow ++;
                    $sRaw = $sRaw + 2;
                    $sMake = $aShift['make'];
                    $sModel = $aShift['model1'];
                    if ($aBookmark['make'] != $aShift['make'])
                    {
                        $sBookmark = $oCatalog->create_bookmark($aShift['make'], sprintf('parent=%d', $sParent));

                        $aBookmark['make'] = $aShift['make'];
                        $aBookmark['model'] = '';
                        $aBookmark['current'] = $sBookmark;
                    }

                    if ($aBookmark['model'] != $sModel)
                    {
                        $aBookmark['model'] = $sModel;
                        $oCatalog->create_bookmark($aShift['model1'], sprintf('parent=%d', $aBookmark['current']));
                        $aVehicle[] = ['make' => $aBookmark['make'], 'model' => $aBookmark['model'], 'page' => $this->aOption['pagination']];
                    }
                }
            }

            if ($sModel != $aShift['model1'])
            {
                if ($sRaw >= 69) {
                    $sData = false;
                }
    
                if ($sData)
                {
                    foreach ([1, 2, 8, 9] as $sCol)
                    {
                        $sOption = '';
                        switch ($sCol)
                        {
                            case 1:
                                $sOption = 'colwidth=%s rowheight=%s fittextline={font=%s fontsize=8 fitmethod=auto position={left center}} margin=2 matchbox={fillcolor=%s}';
                                $sOption = sprintf($sOption, $aPoint[sprintf('cellWidth%d', $sCol)], $aPoint['cellHeight'], $this->aOption['font']['arial_bd'], $this->aOption['colors']['back']);
                                break;
            
                            case 2:
                            case 9:
                                $sOption = 'rowheight=%s fittextline={font=%s fontsize=8 fitmethod=auto} colspan=%d';
                                $sOption = sprintf($sOption, $aPoint['cellHeight'], $this->aOption['font']['arial_bd'], ($sCol == 2) ? 6 : 8);
                                break;
            
                            case 8:
                                $sOption = 'colwidth=%s rowheight=%s fittextline={font=%s fontsize=14 fitmethod=auto position={left center}} margin=2 matchbox={fillcolor=%s}';
                                $sOption = sprintf($sOption, $aPoint[sprintf('cellWidth%d', $sCol)], $aPoint['cellHeight'], $this->aOption['font']['arial_bd'], $this->aOption['colors']['back']);
                                break;
                        }
        
                        $sResult = $oCatalog->addTableCell($sResult, $sCol, $sRow, ($sCol == 1) ? $aShift['model1'] : '', $sOption);
                    }

                    $sModel = $aShift['model1'];
                    if ($aBookmark['model'] != $aShift['model1'])
                    {
                        $aBookmark['model'] = $aShift['model1'];
                        $oCatalog->create_bookmark($aShift['model1'], sprintf('parent=%d', $aBookmark['current']));
                        $aVehicle[] = ['make' => $aBookmark['make'],'model' => $aBookmark['model'], 'page' => $this->aOption['pagination']];
                    }

                    $sRow ++;
                    $sRaw ++;
                }
            }

            // 填充单元格
            $sFirst = true;
            $sCell = $sData;
            $sCount = count($aShift['value']);
            while ($sCell)
            {
                $sStart = $sFirst ? 1 : 2;
                $aData = array_shift($aShift['value']);
                for ($sCol = $sStart; $sCol <= 16; $sCol ++)
                {
                    switch ($sCol)
                    {
                        case 1:
                            // 需要计算rowspan
                            $sFirst = false;
                            $sValue = $aShift['model2'];
                            $sRowspan = (($sCount + $sRaw) > 70) ? (70 - $sRaw) + 1 : $sCount;
                            $sOption = 'colwidth=%s rowheight=%s rowspan=%d fittextline={font=%s fontsize=7 fitmethod=auto position={left %s}} margin=2 matchbox={fillcolor=%s}';
                            $sOption = sprintf($sOption, $aPoint[sprintf('cellWidth%d', $sCol)], $aPoint['cellHeight'] * $sRowspan, $sRowspan, $this->aOption['font']['arial'], ($sRowspan > 1) ? 'top' : 'center', $this->aOption['colors']['back']);
                            break;

                        case 8:
                            $sValue = $aData['col7'];
                            $sOption = 'colwidth=%s rowheight=%s fittextline={font=%s fontsize=7 fitmethod=auto position={left center}} margin=2 matchbox={fillcolor=%s}';
                            $sOption = sprintf($sOption, $aPoint[sprintf('cellWidth%d', $sCol)], $aPoint['cellHeight'], $this->aOption['font']['arial_bd'], $this->aOption['colors']['back']);
                            break;

                        default:
                            $sValue = $aData[sprintf('col%d', $sCol - 1)];
                            $sPosition = (false !== in_array($sCol, $aCenter)) ? '{left center}' : 'center';
                            $sOption = 'colwidth=%s rowheight=%s fittextline={font=%s fontsize=6 fitmethod=auto position=%s} margin=1';
                            $sOption = sprintf($sOption, $aPoint[sprintf('cellWidth%d', $sCol)], $aPoint['cellHeight'], $this->aOption['font']['arial'], $sPosition);
                            break;
                    }

                    $sResult = $oCatalog->addTableCell($sResult, $sCol, $sRow, $sValue, $sOption);
                }

                $sRow ++;
                $sRaw ++;
                if (!$aShift['value'] || ($sRaw > 70)) {
                    $sCell = false;
                }
            }

            // 页面结束
            if (($sRaw > 70) || !$aValue || !$sData)
            {
                // 如当前弹出数据还有剩余, 插回去
                if ($aShift['value']) {
                    array_unshift($aValue, $aShift);
                }
                
                $sOption = 'header=0 rowheightdefault=auto stroke={{line=frame linewidth=1 strokecolor=%s} {line=vert1 linewidth=1 strokecolor=%s} {line=vert7 linewidth=1 strokecolor=%s} {line=vert8 linewidth=1 strokecolor=%s} {line=other linewidth=0.1}}';
                $sOption = sprintf($sOption, $this->aOption['colors']['line'], $this->aOption['colors']['line'], $this->aOption['colors']['line'], $this->aOption['colors']['line']);
                $sResult = $oCatalog->fit_table($sResult, $this->aOption['point']['x1'], $this->aOption['point']['y1'], $this->aOption['point']['x2'], $this->aOption['point']['y2'], $sOption);
                
                $oCatalog = $this->pagination($oCatalog, $this->aOption['pagination']);
                $oCatalog->end_page_ext('');
                $this->aOption['pagination'] ++;
                
                $sRow = 1;
                $sRaw = 1;
                $sMake = '';
                $sModel = '';
                if (!$aValue) {
                    $sWhile = false;
                }
            }
        }
        
        return $sBuffer ? ['vehicle' => $aVehicle, 'pagination' => $this->aOption['pagination'] - 1] : $oCatalog;
    }


    /**
     * 传动轴高端线车型应用
     *
     * @param PDFlib $oCatalog
     * @param array $aValue  数据
     * @param false $sBuffer 是否只返回车型索引页数据 和 车型应用页页码
     *
     * @example
     * [
     *      'style' => 'modelGuideByPropShaftAssembly', // 版式
     *      'value' => [
     *          [
     *              'make' => 'ACURA',
     *              'model1' => 'MDX',
     *              'model2' => '1966-1970',
     *              'remark' => "Quattro ALL (4A, C4) \nWith Sport sus.\nExc. S4",
     *              'value' => [
     *                  ['col1'=> '1990.12-', 'col2' => '1994.07', 'col3'=> 'AT/MT', 'col4' => 'L/R', 'col5' => 'F', 'col6' => 'Engine AR 34103 (09.98-.)', 'col7' => 'Date from:1986.04', 'col8' => '802015', 'col9' => 'Outer Joint', 'col10' => '√', 'col11' => 27, 'col12' => 28, 'col13' => 59, 'col14' => 84, 'col15' => 61.5],
     *                  // ...
     *              ]
     *          ],
     *          // ....
     *      ]
     * ]
     *
     * @return array|PDFlib
     */
    public function modelGuideByPropShaftAssembly(PDFlib $oCatalog, array $aValue, bool $sBuffer = false)
    {
        $aVehicle = [];
        $aPoint = [
            'cellWidth' => $this->aOption['point']['x2'] - $this->aOption['point']['x1'],
            'cellWidth1' => 110, // 车型列宽度
            'cellWidth2' => 50, // 年份列宽度
            'cellWidth3' => 30, // AT/MT
            'cellWidth4' => 15, // FR
            'cellWidth5' => 15, // LR
            'cellWidth6' => 75, // DRIVE TYPE & ENGINE
            'cellWidth7' => 72, // REMARKS
            'cellWidth8' => 33, // GSP
            'cellWidth9' => 34, // product

            'cellWidth10' => 15, // abs
            'cellWidth11' => 15, // A
            'cellWidth12' => 15, // B
            'cellWidth13' => 15, // C
            'cellWidth14' => 15, // H
            'cellWidth15' => 15, // L

            'cellHeight' => 11, // 表格高度
            'cellHeightHeader' => 16.5,

            'pic1' => sprintf('%s/image/%s/wheelCar.png', $this->aOption['resources'], $this->aOption['color']),
            'pic2' => sprintf('%s/image/%s/WaterPumpYear.png', $this->aOption['resources'], $this->aOption['color']),
            'pic9' => sprintf('%s/image/%s/8.png', $this->aOption['resources'], $this->aOption['color']),
            'pic10' => sprintf('%s/image/%s/abs.png', $this->aOption['resources'], $this->aOption['color']),
        ];

        $aHeader = [
            1 => [
                1 => [2, 1, '', 9],
                2 => [2, 1, 'YEAR', 9],
                3 => [2, 1, 'TRANSM.', 5],
                4 => [2, 1, 'F/R', 6],
                5 => [2, 1, 'L/R', 6],
                6 => [2, 1, 'BODY STYLE & DRIVE TYPE & ENGINE', 6],
                7 => [2, 1, 'REMARKS', 9],
                8 => [2, 1, $this->aOption['gTitle'], 7],
                9 => [2, 1, 'PRODUCT', 6],
                10 => [2, 1, 'ABS', 5],
                11 => [1, 5, 'Technical Specifications', 7],
            ],
            2 => [
                11 => [1, 1, 'A', 9],
                12 => [1, 1, 'B', 9],
                13 => [1, 1, 'C', 9],
                14 => [1, 1, 'H', 9],
                15 => [1, 1, 'L', 9],
            ]
        ];

        // 内容页面
        $sRow = 1;
        $sRaw = 1;
        $sMake = '';
        $sModel = '';
        $sData = true;
        $sWhile = true;
        $sParent = 0;
        $sResult = 0;
        $aCenter = [2, 6, 7, 9];
        $sRemark = $aValue['remark'] ?? '';
        $aValue = $aValue['value'];
        $aBookmark = ['make' => '', 'model' => '', 'current' => 0];
        while ($sWhile)
        {
            // 页面开始
            if ($sRow == 1)
            {
                $sData = true;
                $sResult = 0;
                $oCatalog->begin_page_ext(0, 0, 'width=a4.width height=a4.height');

                // 分部书签
                if (!$sParent && $sRemark) {
                    $sParent = $oCatalog->create_bookmark($sRemark, sprintf('parent=%d', 0));
                }

                foreach ($aHeader as $sRow => $aVal)
                {
                    foreach ($aVal as $sCol => $aCol)
                    {
                        switch ($sCol)
                        {
                            case 1:
                                $oImage = $oCatalog->loadImage('auto', $aPoint[sprintf('pic%d', $sCol)], '');
                                $sOption = 'colwidth=%s rowheight=%s image=%s fitimage={position={center}} matchbox={fillcolor=%s} rowspan=%d colspan=%d margin=1.5';
                                $sOption = sprintf($sOption, $aPoint[sprintf('cellWidth%d', $sCol)], $aPoint['cellHeightHeader'] * $aCol[0], $oImage, $this->aOption['colors']['back'], $aCol[0], $aCol[1]);
                                break;

                            case 2:
                            case 9:
                            case 10:
                                $oImage = $oCatalog->loadImage('auto', $aPoint[sprintf('pic%d', $sCol)], '');
                                $sOption = 'colwidth=%s rowheight=%s image=%s fitimage={position={center bottom}} fittextline={font=%s fontsize=7 fillcolor=%s fitmethod=auto position={center bottom}} rowspan=%d colspan=%d margin=1.5';
                                $sOption = sprintf($sOption, $aPoint[sprintf('cellWidth%d', $sCol)], $aPoint['cellHeightHeader'] * $aCol[0], $oImage, $this->aOption['font']['arial_bd'],$this->aOption['colors']['font'], $aCol[0], $aCol[1]);
                                break;

                            default:
                                $sColor = ($sCol == 8) ? $this->aOption['colors']['back'] : $this->aOption['colors']['white'];
                                $sOption = 'colwidth=%s rowheight=%s fittextline={font=%s fontsize=%d fitmethod=auto fillcolor=%s} matchbox={fillcolor=%s} rowspan=%d colspan=%d margin=1.5';
                                $sOption = sprintf($sOption, $aPoint[sprintf('cellWidth%d', $sCol)], $aPoint['cellHeightHeader'] * $aCol[0], $this->aOption['font']['arial_bd'], $aCol[3], $this->aOption['colors']['font'], $sColor, $aCol[0], $aCol[1]);
                                break;
                        }
                        $sResult = $oCatalog->addTableCell($sResult, $sCol, $sRow, $aCol[2], $sOption);
                    }
                }

                $sRow ++;
                $sRaw = $sRaw + 3;
            }
            $aShift = array_shift($aValue);

            // 车型列
            if ($sMake != $aShift['make'])
            {
                if ($sRaw >= 67) {
                    $sData = false;
                }

                if ($sData)
                {
                    foreach ([1, 2, 8, 9] as $sCol)
                    {
                        switch ($sCol)
                        {
                            case 1:
                                $sChild = 0;
                                $sOption = 'colwidth=%s rowheight=%s fittextline={font=%s fontsize=10 fitmethod=auto position={left center}} matchbox={fillcolor=%s} margin=1.5';
                                $sOption = sprintf($sOption, $aPoint['cellWidth1'], $aPoint['cellHeight'], $this->aOption['font']['arial_bd'], $this->aOption['colors']['back']);
                                $sChild = $oCatalog->addTableCell($sChild, 1, 1, $aShift['make'], $sOption);

                                $sOption = 'colwidth=%s rowheight=%s fittextline={font=%s fontsize=8 fitmethod=auto position={left center}} matchbox={fillcolor=%s} margin=2';
                                $sOption = sprintf($sOption, $aPoint['cellWidth1'], $aPoint['cellHeight'], $this->aOption['font']['arial_bd'], $this->aOption['colors']['back']);
                                $sChild = $oCatalog->addTableCell($sChild, 1, 2, $aShift['model1'], $sOption);

                                $sOption = 'header=0 rowheightdefault=auto stroke={{line=other linewidth=0}}';
                                $sChild = $oCatalog->fit_table(
                                    $sChild,
                                    $this->aOption['point']['x1'],
                                    $this->aOption['point']['y2'] - ($sRaw + 1) * $aPoint['cellHeight'],
                                    $this->aOption['point']['x1'] + $aPoint['cellWidth1'],
                                    $this->aOption['point']['y2'] - ($sRaw - 1) * $aPoint['cellHeight'],
                                    $sOption
                                );

                                $sOption = 'colwidth=%s rowheight=%s';
                                $sOption = sprintf($sOption, $aPoint[sprintf('cellWidth%d', $sCol)], $aPoint['cellHeight'] * 2);
                                break;

                            case 2:
                            case 9:
                                $sOption = 'rowheight=%s fittextline={font=%s fontsize=8 fitmethod=auto} colspan=%d';
                                $sOption = sprintf($sOption, $aPoint['cellHeight'] * 2, $this->aOption['font']['arial_bd'], ($sCol == 2) ? 6 : 7);
                                break;

                            case 8:
                                $sOption = 'colwidth=%s rowheight=%s fittextline={font=%s fontsize=14 fitmethod=auto position={left center}} margin=2 matchbox={fillcolor=%s}';
                                $sOption = sprintf($sOption, $aPoint[sprintf('cellWidth%d', $sCol)], $aPoint['cellHeight'] * 2, $this->aOption['font']['arial_bd'], $this->aOption['colors']['back']);
                                break;

                            default: $sOption = ''; break;
                        }

                        $sResult = $oCatalog->addTableCell($sResult, $sCol, $sRow, '', $sOption);
                    }

                    $sRow ++;
                    $sRaw = $sRaw + 2;
                    $sMake = $aShift['make'];
                    $sModel = $aShift['model1'];
                    if ($aBookmark['make'] != $aShift['make'])
                    {
                        $sBookmark = $oCatalog->create_bookmark($aShift['make'], sprintf('parent=%d', $sParent));

                        $aBookmark['make'] = $aShift['make'];
                        $aBookmark['model'] = '';
                        $aBookmark['current'] = $sBookmark;
                    }

                    if ($aBookmark['model'] != $sModel)
                    {
                        $aBookmark['model'] = $sModel;
                        $oCatalog->create_bookmark($aShift['model1'], sprintf('parent=%d', $aBookmark['current']));
                        $aVehicle[] = ['make' => $aBookmark['make'], 'model' => $aBookmark['model'], 'page' => $this->aOption['pagination']];
                    }
                }
            }

            if ($sModel != $aShift['model1'])
            {
                if ($sRaw >= 69) {
                    $sData = false;
                }

                if ($sData)
                {
                    foreach ([1, 2, 8, 9] as $sCol)
                    {
                        $sOption = '';
                        switch ($sCol)
                        {
                            case 1:
                                $sOption = 'colwidth=%s rowheight=%s fittextline={font=%s fontsize=8 fitmethod=auto position={left center}} margin=2 matchbox={fillcolor=%s}';
                                $sOption = sprintf($sOption, $aPoint[sprintf('cellWidth%d', $sCol)], $aPoint['cellHeight'], $this->aOption['font']['arial_bd'], $this->aOption['colors']['back']);
                                break;

                            case 2:
                            case 9:
                                $sOption = 'rowheight=%s fittextline={font=%s fontsize=8 fitmethod=auto} colspan=%d';
                                $sOption = sprintf($sOption, $aPoint['cellHeight'], $this->aOption['font']['arial_bd'], ($sCol == 2) ? 6 : 7);
                                break;

                            case 8:
                                $sOption = 'colwidth=%s rowheight=%s fittextline={font=%s fontsize=14 fitmethod=auto position={left center}} margin=2 matchbox={fillcolor=%s}';
                                $sOption = sprintf($sOption, $aPoint[sprintf('cellWidth%d', $sCol)], $aPoint['cellHeight'], $this->aOption['font']['arial_bd'], $this->aOption['colors']['back']);
                                break;
                        }

                        $sResult = $oCatalog->addTableCell($sResult, $sCol, $sRow, ($sCol == 1) ? $aShift['model1'] : '', $sOption);
                    }

                    $sModel = $aShift['model1'];
                    if ($aBookmark['model'] != $aShift['model1'])
                    {
                        $aBookmark['model'] = $aShift['model1'];
                        $oCatalog->create_bookmark($aShift['model1'], sprintf('parent=%d', $aBookmark['current']));
                        $aVehicle[] = ['make' => $aBookmark['make'],'model' => $aBookmark['model'], 'page' => $this->aOption['pagination']];
                    }

                    $sRow ++;
                    $sRaw ++;
                }
            }

            // 填充单元格
            $sFirst = true;
            $sCell = $sData;
            $sCount = count($aShift['value']);
            while ($sCell)
            {
                $sStart = $sFirst ? 1 : 2;
                $aData = array_shift($aShift['value']);
                for ($sCol = $sStart; $sCol <= 15; $sCol ++)
                {
                    switch ($sCol)
                    {
                        case 1:
                            // 需要计算rowspan
                            $sFirst = false;
                            $sValue = $aShift['model2'];
                            $sRowspan = (($sCount + $sRaw) > 70) ? (70 - $sRaw) + 1 : $sCount;
                            $sOption = 'colwidth=%s rowheight=%s rowspan=%d fittextline={font=%s fontsize=7 fitmethod=auto position={left %s}} margin=2 matchbox={fillcolor=%s}';
                            $sOption = sprintf($sOption, $aPoint[sprintf('cellWidth%d', $sCol)], $aPoint['cellHeight'] * $sRowspan, $sRowspan, $this->aOption['font']['arial'], ($sRowspan > 1) ? 'top' : 'center', $this->aOption['colors']['back']);
                            break;

                        case 8:
                            $sValue = $aData['col7'];
                            $sOption = 'colwidth=%s rowheight=%s fittextline={font=%s fontsize=7 fitmethod=auto position={left center}} margin=2 matchbox={fillcolor=%s}';
                            $sOption = sprintf($sOption, $aPoint[sprintf('cellWidth%d', $sCol)], $aPoint['cellHeight'], $this->aOption['font']['arial_bd'], $this->aOption['colors']['back']);
                            break;

                        default:
                            $sValue = $aData[sprintf('col%d', $sCol - 1)];
                            $sPosition = (false !== in_array($sCol, $aCenter)) ? '{left center}' : 'center';
                            $sOption = 'colwidth=%s rowheight=%s fittextline={font=%s fontsize=6 fitmethod=auto position=%s} margin=1';
                            $sOption = sprintf($sOption, $aPoint[sprintf('cellWidth%d', $sCol)], $aPoint['cellHeight'], $this->aOption['font']['arial'], $sPosition);
                            break;
                    }

                    $sResult = $oCatalog->addTableCell($sResult, $sCol, $sRow, $sValue, $sOption);
                }

                $sRow ++;
                $sRaw ++;
                if (!$aShift['value'] || ($sRaw > 70)) {
                    $sCell = false;
                }
            }

            // 页面结束
            if (($sRaw > 70) || !$aValue || !$sData)
            {
                // 如当前弹出数据还有剩余, 插回去
                if ($aShift['value']) {
                    array_unshift($aValue, $aShift);
                }

                $sOption = 'header=0 rowheightdefault=auto stroke={{line=frame linewidth=1 strokecolor=%s} {line=vert1 linewidth=1 strokecolor=%s} {line=vert7 linewidth=1 strokecolor=%s} {line=vert8 linewidth=1 strokecolor=%s} {line=other linewidth=0.1}}';
                $sOption = sprintf($sOption, $this->aOption['colors']['line'], $this->aOption['colors']['line'], $this->aOption['colors']['line'], $this->aOption['colors']['line']);
                $sResult = $oCatalog->fit_table($sResult, $this->aOption['point']['x1'], $this->aOption['point']['y1'], $this->aOption['point']['x2'], $this->aOption['point']['y2'], $sOption);

                $oCatalog = $this->pagination($oCatalog, $this->aOption['pagination']);
                $oCatalog->end_page_ext('');
                $this->aOption['pagination'] ++;

                $sRow = 1;
                $sRaw = 1;
                $sMake = '';
                $sModel = '';
                if (!$aValue) {
                    $sWhile = false;
                }
            }
        }

        return $sBuffer ? ['vehicle' => $aVehicle, 'pagination' => $this->aOption['pagination'] - 1] : $oCatalog;
    }

    /**
     * 悬挂件车型应用
     *
     * @param PDFlib $oCatalog
     * @param array $aValue  数据
     * @param false $sBuffer 是否只返回车型索引页数据 和 车型应用页页码
     *
     * @example
     * [
     *      'style' => 'modelGuideBySuspension', // 版式
     *      'value' => [
     *          [
     *              'make' => 'ACURA',
     *              'model1' => 'MDX',
     *              'model2' => '1966-1970',
     *              'remark' => "Quattro ALL (4A, C4) \nWith Sport sus.\nExc. S4",
     *              'value' => [
     *                  [
     *                      'col1' => '1990.12-1994.07',
     *                      'col2' => 'Front',
     *                      'col3' => 'AWD Engine AAR (12.90-.)',
     *                      'col4' => 'remark',
     *                      'col5' => 'Mounting,Radiator',
     *                      'col6' => '512205'
     *                  ]
     *                  // ...
     *              ]
     *          ],
     *          // ....
     *      ]
     * ]
     *
     * @return array|PDFlib
     */
    public function modelGuideBySuspension(PDFlib $oCatalog, array $aValue, bool $sBuffer = false)
    {
        $aVehicle = [];
        $aPoint = [
            'cellWidth' => $this->aOption['point']['x2'] - $this->aOption['point']['x1'],
            'cellWidth1' => 107, // 车型列宽度
            'cellWidth2' => 53, // 年份列宽度
            'cellWidth3' => 80, //
            'cellWidth4' => 96, //
            'cellWidth5' => 73, //
            'cellWidth6' => 70, //
            'cellWidth7' => 46, //
            'cellHeight' => 11, // 表格高度
            
            'car' => sprintf('%s/image/%s/wheelCar.png', $this->aOption['resources'], $this->aOption['color']),
            'year' => sprintf('%s/image/%s/WaterPumpYear.png', $this->aOption['resources'], $this->aOption['color']),
        ];
        
        // 内容页面
        $sRow = 1;
        $sRaw = 1;
        $sMake = '';
        $sModel = '';
        $sData = true;
        $sWhile = true;
        
        $sParent = 0;
        $sResult = 0;
        $sRemark = $aValue['remark'] ?? '';
        $aValue = $aValue['value'];
        $aBookmark = ['make' => '', 'model' => '', 'current' => 0];
        $aMatch = [1 => '', 'YEAR', 'FITTING POSITION', 'BODY STYLE & DRIVE TYPE & ENGINE', 'REMARKS', 'PRODUCT', $this->aOption['gTitle']];
        while ($sWhile)
        {
            // 页面开始
            if ($sRow == 1)
            {
                $sData = true;
                $sResult = 0;
                $oCatalog->begin_page_ext(0, 0, 'width=a4.width height=a4.height');
                // 分部书签
                if (!$sParent && $sRemark) {
                    $sParent = $oCatalog->create_bookmark($sRemark, sprintf('parent=%d', 0));
                }
                
                for ($sCol = 1; $sCol <= 7; $sCol ++)
                {
                    switch ($sCol)
                    {
                        case 1:
                            $oImage = $oCatalog->loadImage('auto', $aPoint['car'], '');
                            $sOption = 'colwidth=%s rowheight=%s image=%s fitimage={position={center}} fittextline={font=%s fontsize=9 fitmethod=auto} matchbox={fillcolor=%s} margin=1.5';
                            $sOption = sprintf($sOption, $aPoint[sprintf('cellWidth%d', $sCol)], $aPoint['cellHeight'] * 4, $oImage, $this->aOption['font']['arial_bd'], $this->aOption['colors']['back']);
                            break;
                        
                        case 2:
                            $oImage = $oCatalog->loadImage('auto', $aPoint['year'], '');
                            $sOption = 'colwidth=%s rowheight=%s image=%s fitimage={position={center bottom}} fittextline={font=%s fontsize=9 fitmethod=auto fillcolor=%s position={center bottom}} margin=5';
                            $sOption = sprintf($sOption, $aPoint[sprintf('cellWidth%d', $sCol)], $aPoint['cellHeight'] * 4, $oImage, $this->aOption['font']['arial_bd'], $this->aOption['colors']['font']);
                            break;
                        
                        case 3:
                        case 4:
                        case 5:
                        case 6:
                            $sOption = 'colwidth=%s rowheight=%s fittextline={font=%s fontsize=9 fitmethod=auto fillcolor=%s} margin=2';
                            $sOption = sprintf($sOption, $aPoint[sprintf('cellWidth%d', $sCol)], $aPoint['cellHeight'] * 4, $this->aOption['font']['arial_bd'], $this->aOption['colors']['font']);
                            break;
                        
                        case 7:
                            $sOption = 'colwidth=%s rowheight=%s fittextline={font=%s fontsize=9 fitmethod=auto fillcolor=%s} matchbox={fillcolor=%s} margin=1.5';
                            $sOption = sprintf($sOption, $aPoint[sprintf('cellWidth%d', $sCol)], $aPoint['cellHeight'] * 4, $this->aOption['font']['arial_bd'], $this->aOption['colors']['font'], $this->aOption['colors']['back']);
                            break;
                    }
                    
                    $sResult = $oCatalog->addTableCell($sResult, $sCol, $sRow, $aMatch[$sCol], $sOption);
                }
                $sRow ++;
                $sRaw = $sRaw + 4;
            }
            
            // 抽取数据
            $aShift = array_shift($aValue);
            
            // 车型列
            if ($sMake != $aShift['make'])
            {
                if ($sRaw >= 67) {
                    $sData = false;
                }
                
                if ($sData)
                {
                    for ($sCol = 1; $sCol <= 7; $sCol ++)
                    {
                        switch ($sCol)
                        {
                            case 1:
                                // 解决超出问题
                                $sChild = 0;
                                $sOption = 'colwidth=%s rowheight=%s fittextline={font=%s fontsize=10 fitmethod=auto position={left center}} matchbox={fillcolor=%s} margin=2';
                                $sOption = sprintf($sOption, $aPoint['cellWidth1'], $aPoint['cellHeight'], $this->aOption['font']['arial_bd'], $this->aOption['colors']['back']);
                                $sChild = $oCatalog->addTableCell($sChild, 1, 1, $aShift['make'], $sOption);
    
                                $sOption = 'colwidth=%s rowheight=%s fittextline={font=%s fontsize=8 fitmethod=auto position={left center}} matchbox={fillcolor=%s} margin=2';
                                $sOption = sprintf($sOption, $aPoint['cellWidth1'], $aPoint['cellHeight'], $this->aOption['font']['arial_bd'], $this->aOption['colors']['back']);
                                $sChild = $oCatalog->addTableCell($sChild, 1, 2, $aShift['model1'], $sOption);
    
                                $sOption = 'header=0 rowheightdefault=auto stroke={{line=other linewidth=0}}';
                                $sChild = $oCatalog->fit_table(
                                    $sChild,
                                    $this->aOption['point']['x1'],
                                    $this->aOption['point']['y2'] - ($sRaw + 1) * $aPoint['cellHeight'],
                                    $this->aOption['point']['x1'] + $aPoint['cellWidth1'],
                                    $this->aOption['point']['y2'] - ($sRaw - 1) * $aPoint['cellHeight'],
                                    $sOption
                                );
                                
                                $sOption = 'colwidth=%s rowheight=%s';
                                $sOption = sprintf($sOption, $aPoint[sprintf('cellWidth%d', $sCol)], $aPoint['cellHeight'] * 2);
                                $sResult = $oCatalog->addTableCell($sResult, $sCol, $sRow, '', $sOption);
                                break;
                                
                            default:
                                $sColor = ($sCol == 7) ? $this->aOption['colors']['back'] : $this->aOption['colors']['white'];
                                $sOption = 'colwidth=%s rowheight=%s fittextline={font=%s fontsize=14 fitmethod=auto position={left center}} margin=2 matchbox={fillcolor=%s}';
                                $sOption = sprintf($sOption, $aPoint[sprintf('cellWidth%d', $sCol)], $aPoint['cellHeight'] * 2, $this->aOption['font']['arial_bd'], $sColor);
                                $sResult = $oCatalog->addTableCell($sResult, $sCol, $sRow, ($sCol == 1) ? $aShift['make'] : '', $sOption);
                                break;
                        }
                    }
                    
                    $sRow ++;
                    $sRaw = $sRaw + 2;
                    $sMake = $aShift['make'];
                    $sModel = $aShift['model1'];

                    if ($aBookmark['make'] != $aShift['make'])
                    {
                        $sBookmark = $oCatalog->create_bookmark($aShift['make'], sprintf('parent=%d', $sParent));
                        $aBookmark['make'] = $aShift['make'];
                        $aBookmark['model'] = '';
                        $aBookmark['current'] = $sBookmark;
                    }

                    if ($aBookmark['model'] != $aShift['model1'])
                    {
                        $aBookmark['model'] = $aShift['model1'];
                        $oCatalog->create_bookmark($aShift['model1'], sprintf('parent=%d', $aBookmark['current']));
                        $aVehicle[] = ['make' => $aBookmark['make'], 'model' => $aBookmark['model'], 'page' => $this->aOption['pagination']];
                    }
                }
            }
            
            if ($aShift['model1'] != $sModel)
            {
                if ($sRaw >= 69) {
                    $sData = false;
                }
                
                if ($sData)
                {
                    for ($sCol = 1; $sCol <= 7; $sCol ++)
                    {
                        $sColor = (($sCol == 1) || ($sCol == 7)) ? $this->aOption['colors']['back']: $this->aOption['colors']['white'];
                        $sOption = 'colwidth=%s rowheight=%s fittextline={font=%s fontsize=8 fitmethod=auto position={left center}} margin=2 matchbox={fillcolor=%s}';
                        $sOption = sprintf($sOption, $aPoint[sprintf('cellWidth%d', $sCol)], $aPoint['cellHeight'], $this->aOption['font']['arial_bd'], $sColor);
                        $sResult = $oCatalog->addTableCell($sResult, $sCol, $sRow, ($sCol == 1) ? $aShift['model1'] : '', $sOption);
                    }
                    
                    $sModel = $aShift['model1'];
                    if ($aBookmark['model'] != $aShift['model1'])
                    {
                        $aBookmark['model'] = $aShift['model1'];
                        $oCatalog->create_bookmark($aShift['model1'], sprintf('parent=%d', $aBookmark['current']));
                        $aVehicle[] = ['make' => $aBookmark['make'],'model' => $aBookmark['model'], 'page' => $this->aOption['pagination']];
                    }

                    $sRow ++;
                    $sRaw ++;
                }
            }
            
            // 填充单元格
            $sFirst = true;
            $sCell = $sData;
            $sCount = count($aShift['value']);
            while ($sCell)
            {
                $sStart = $sFirst ? 1 : 2;
                $aData = array_shift($aShift['value']);
                for ($sCol = $sStart; $sCol <= 7; $sCol ++)
                {
                    $sValue = '';
                    $sOption = '';
                    switch ($sCol)
                    {
                        case 1:
                            // 需要计算rowspan
                            $sFirst = false;
                            $sValue = $aShift['model2'];
                            $sOption = 'colwidth=%s rowheight=%s rowspan=%d fittextline={font=%s fontsize=7 fitmethod=auto position={left top}} margin=2 matchbox={fillcolor=%s}';
                            $sRowspan = (($sCount + $sRaw) > 70) ? (70 - $sRaw) + 1 : $sCount;
                            if ($sRowspan <= 0) {
                                dd($sRowspan);
                            }
                            $sOption = sprintf($sOption, $aPoint[sprintf('cellWidth%d', $sCol)], $aPoint['cellHeight'] * $sRowspan, $sRowspan, $this->aOption['font']['arial'], $this->aOption['colors']['back']);
                            break;
                        
                        case 2:
                            $sValue = $aData['col1'];
                            $sOption = 'colwidth=%s rowheight=%s fittextline={font=%s fontsize=7 fitmethod=auto position={left center}} margin=2';
                            $sOption = sprintf($sOption, $aPoint[sprintf('cellWidth%d', $sCol)], $aPoint['cellHeight'], $this->aOption['font']['arial']);
                            break;
                        
                        case 3:
                            $sValue = $aData['col2'];
                            $sOption = 'colwidth=%s rowheight=%s fittextline={font=%s fontsize=7 fitmethod=auto position={left center}} margin=2';
                            $sOption = sprintf($sOption, $aPoint[sprintf('cellWidth%d', $sCol)], $aPoint['cellHeight'], $this->aOption['font']['arial']);
                            break;
                        
                        case 4:
                            $sValue = $aData['col3'];
                            $sOption = 'colwidth=%s rowheight=%s fittextline={font=%s fontsize=7 fitmethod=auto position={left center}} margin=2';
                            $sOption = sprintf($sOption, $aPoint[sprintf('cellWidth%d', $sCol)], $aPoint['cellHeight'], $this->aOption['font']['arial']);
                            break;
                        
                        case 5:
                            $sValue = $aData['col4'];
                            $sOption = 'colwidth=%s rowheight=%s fittextline={font=%s fontsize=7 fitmethod=auto position={left center}} margin=2';
                            $sOption = sprintf($sOption, $aPoint[sprintf('cellWidth%d', $sCol)], $aPoint['cellHeight'], $this->aOption['font']['arial']);
                            break;

                        case 6:
                            $sValue = $aData['col5'];
                            $sOption = 'colwidth=%s rowheight=%s fittextline={font=%s fontsize=7 fitmethod=auto position={left center}} margin=2';
                            $sOption = sprintf($sOption, $aPoint[sprintf('cellWidth%d', $sCol)], $aPoint['cellHeight'], $this->aOption['font']['arial']);
                            break;
                        
                        case 7:
                            $sValue = $aData['col6'];
                            $sOption = 'colwidth=%s rowheight=%s fittextline={font=%s fontsize=7 fitmethod=auto position={left center}} margin=2 matchbox={fillcolor=%s}';
                            $sOption = sprintf($sOption, $aPoint[sprintf('cellWidth%d', $sCol)], $aPoint['cellHeight'], $this->aOption['font']['arial_bd'], $this->aOption['colors']['back']);
                            break;
                    }
                    
                    $sResult = $oCatalog->addTableCell($sResult, $sCol, $sRow, $sValue, $sOption);
                }
                
                $sRow ++;
                $sRaw ++;
                if (!$aShift['value'] || ($sRaw > 70)) {
                    $sCell = false;
                }
            }
            
            // 页面结束
            if (($sRaw >= 70) || !$aValue || !$sData)
            {
                // 如当前弹出数据还有剩余, 插回去
                if ($aShift['value']) {
                    array_unshift($aValue, $aShift);
                }
                
                $sOption = 'header=0 rowheightdefault=auto stroke={
                        {line=frame linewidth=1 strokecolor=%s} 
                        {line=vert1 linewidth=1 strokecolor=%s}
                        {line=vert5 linewidth=1 strokecolor=%s}
                        {line=hor1 linewidth=1 strokecolor=%s}
                        {line=other linewidth=0.5 strokecolor=%s}
                    }';
                $sOption = sprintf($sOption, $this->aOption['colors']['line'], $this->aOption['colors']['line'], $this->aOption['colors']['line'], $this->aOption['colors']['line'], $this->aOption['colors']['black']);
                $sResult = $oCatalog->fit_table($sResult, $this->aOption['point']['x1'], $this->aOption['point']['y1'], $this->aOption['point']['x2'], $this->aOption['point']['y2'], $sOption);
                
                $oCatalog = $this->pagination($oCatalog, $this->aOption['pagination']);
                $oCatalog->end_page_ext('');
                
                $sRow = 1;
                $sRaw = 1;
                $sMake = '';
                $sModel = '';
                $this->aOption['pagination'] ++;
                if (!$aValue) {
                    $sWhile = false;
                }
            }
        }
        return $sBuffer ? ['vehicle' => $aVehicle, 'pagination' => $this->aOption['pagination'] - 1] : $oCatalog;
    }


    /**
     * 传感器车型应用
     *
     * @param PDFlib $oCatalog
     * @param array $aValue  数据
     * @param false $sBuffer 是否只返回车型索引页数据 和 车型应用页页码
     *
     * @example
     * [
     *      'style' => 'modelGuideBySensor', // 版式
     *      'value' => [
     *          [
     *              'make' => 'ACURA',
     *              'model1' => 'MDX',
     *              'model2' => '1966-1970',
     *              'remark' => "Quattro ALL (4A, C4) \nWith Sport sus.\nExc. S4",
     *              'value' => [
     *                  [
     *                      'col1' => '1990.12-1994.07',
     *                      'col2' => 'Front',
     *                      'col3' => 'AWD Engine AAR (12.90-.)',
     *                      'col4' => 'remark',
     *                      'col5' => 'Mounting,Radiator',
     *                      'col6' => '512205'
     *                      'col7' => '123'
     *                  ]
     *                  // ...
     *              ]
     *          ],
     *          // ....
     *      ]
     * ]
     *
     * @return array|PDFlib
     */
    public function modelGuideBySensor(PDFlib $oCatalog, array $aValue, bool $sBuffer = false)
    {
        $aVehicle = [];
        $aPoint = [
            'cellWidth' => $this->aOption['point']['x2'] - $this->aOption['point']['x1'],
            'cellWidth1' => 102, // 车型列宽度 -5
            'cellWidth2' => 53, // 年份列宽度
            'cellWidth3' => 75, // FITTING POSITION - 5
            'cellWidth4' => 95, // BODY STYLE & DRIVE TYPE & ENGINE -1
            'cellWidth5' => 70, // REMARKS -3
            'cellWidth6' => 65, // PRODUCT -5
            'cellWidth7' => 42, // GSP -1
            'cellWidth8' => 23, // LENGTH
            'cellHeight' => 11, // 表格高度

            'car' => sprintf('%s/image/%s/wheelCar.png', $this->aOption['resources'], $this->aOption['color']),
            'year' => sprintf('%s/image/%s/WaterPumpYear.png', $this->aOption['resources'], $this->aOption['color']),
        ];

        // 内容页面
        $sRow = 1;
        $sRaw = 1;
        $sMake = '';
        $sModel = '';
        $sData = true;
        $sWhile = true;

        $sParent = 0;
        $sResult = 0;
        $sRemark = $aValue['remark'] ?? '';
        $aValue = $aValue['value'];
        $aBookmark = ['make' => '', 'model' => '', 'current' => 0];
        $aMatch = [
            1 => '',
            'YEAR',
            'FITTING POSITION',
            'BODY STYLE & DRIVE TYPE & ENGINE',
            'REMARKS',
            'USE TYPE',
            $this->aOption['gTitle'],
            'LENGTH'
        ];
        while ($sWhile)
        {
            // 页面开始
            if ($sRow == 1)
            {
                $sData = true;
                $sResult = 0;
                $oCatalog->begin_page_ext(0, 0, 'width=a4.width height=a4.height');
                // 分部书签
                if (!$sParent && $sRemark) {
                    $sParent = $oCatalog->create_bookmark($sRemark, sprintf('parent=%d', 0));
                }

                for ($sCol = 1; $sCol <= 8; $sCol ++)
                {
                    switch ($sCol)
                    {
                        case 1:
                            $oImage = $oCatalog->loadImage('auto', $aPoint['car'], '');
                            $sOption = 'colwidth=%s rowheight=%s image=%s fitimage={position={center}} fittextline={font=%s fontsize=9 fitmethod=auto} matchbox={fillcolor=%s} margin=1.5';
                            $sOption = sprintf($sOption, $aPoint[sprintf('cellWidth%d', $sCol)], $aPoint['cellHeight'] * 4, $oImage, $this->aOption['font']['arial_bd'], $this->aOption['colors']['back']);
                            break;

                        case 2:
                            $oImage = $oCatalog->loadImage('auto', $aPoint['year'], '');
                            $sOption = 'colwidth=%s rowheight=%s image=%s fitimage={position={center bottom}} fittextline={font=%s fontsize=9 fitmethod=auto fillcolor=%s position={center bottom}} margin=5';
                            $sOption = sprintf($sOption, $aPoint[sprintf('cellWidth%d', $sCol)], $aPoint['cellHeight'] * 4, $oImage, $this->aOption['font']['arial_bd'], $this->aOption['colors']['font']);
                            break;

                        case 3:
                        case 4:
                        case 5:
                        case 6:
                        case 8:
                            $sOption = 'colwidth=%s rowheight=%s fittextline={font=%s fontsize=9 fitmethod=auto fillcolor=%s} margin=2';
                            $sOption = sprintf($sOption, $aPoint[sprintf('cellWidth%d', $sCol)], $aPoint['cellHeight'] * 4, $this->aOption['font']['arial_bd'], $this->aOption['colors']['font']);
                            break;

                        case 7:
                            $sOption = 'colwidth=%s rowheight=%s fittextline={font=%s fontsize=9 fitmethod=auto fillcolor=%s} matchbox={fillcolor=%s} margin=1.5';
                            $sOption = sprintf($sOption, $aPoint[sprintf('cellWidth%d', $sCol)], $aPoint['cellHeight'] * 4, $this->aOption['font']['arial_bd'], $this->aOption['colors']['font'], $this->aOption['colors']['back']);
                            break;
                    }

                    $sResult = $oCatalog->addTableCell($sResult, $sCol, $sRow, $aMatch[$sCol], $sOption);
                }
                $sRow ++;
                $sRaw = $sRaw + 4;
            }

            // 抽取数据
            $aShift = array_shift($aValue);

            // 车型列
            if ($sMake != $aShift['make'])
            {
                if ($sRaw >= 67) {
                    $sData = false;
                }

                if ($sData)
                {
                    for ($sCol = 1; $sCol <= 8; $sCol ++)
                    {
                        switch ($sCol)
                        {
                            case 1:
                                // 解决超出问题
                                $sChild = 0;
                                $sOption = 'colwidth=%s rowheight=%s fittextline={font=%s fontsize=10 fitmethod=auto position={left center}} matchbox={fillcolor=%s} margin=2';
                                $sOption = sprintf($sOption, $aPoint['cellWidth1'], $aPoint['cellHeight'], $this->aOption['font']['arial_bd'], $this->aOption['colors']['back']);
                                $sChild = $oCatalog->addTableCell($sChild, 1, 1, $aShift['make'], $sOption);

                                $sOption = 'colwidth=%s rowheight=%s fittextline={font=%s fontsize=8 fitmethod=auto position={left center}} matchbox={fillcolor=%s} margin=2';
                                $sOption = sprintf($sOption, $aPoint['cellWidth1'], $aPoint['cellHeight'], $this->aOption['font']['arial_bd'], $this->aOption['colors']['back']);
                                $sChild = $oCatalog->addTableCell($sChild, 1, 2, $aShift['model1'], $sOption);

                                $sOption = 'header=0 rowheightdefault=auto stroke={{line=other linewidth=0}}';
                                $sChild = $oCatalog->fit_table(
                                    $sChild,
                                    $this->aOption['point']['x1'],
                                    $this->aOption['point']['y2'] - ($sRaw + 1) * $aPoint['cellHeight'],
                                    $this->aOption['point']['x1'] + $aPoint['cellWidth1'],
                                    $this->aOption['point']['y2'] - ($sRaw - 1) * $aPoint['cellHeight'],
                                    $sOption
                                );

                                $sOption = 'colwidth=%s rowheight=%s';
                                $sOption = sprintf($sOption, $aPoint[sprintf('cellWidth%d', $sCol)], $aPoint['cellHeight'] * 2);
                                $sResult = $oCatalog->addTableCell($sResult, $sCol, $sRow, '', $sOption);
                                break;

                            default:
                                $sColor = ($sCol == 7) ? $this->aOption['colors']['back'] : $this->aOption['colors']['white'];
                                $sOption = 'colwidth=%s rowheight=%s fittextline={font=%s fontsize=14 fitmethod=auto position={left center}} margin=2 matchbox={fillcolor=%s}';
                                $sOption = sprintf($sOption, $aPoint[sprintf('cellWidth%d', $sCol)], $aPoint['cellHeight'] * 2, $this->aOption['font']['arial_bd'], $sColor);
                                $sResult = $oCatalog->addTableCell($sResult, $sCol, $sRow, ($sCol == 1) ? $aShift['make'] : '', $sOption);
                                break;
                        }
                    }

                    $sRow ++;
                    $sRaw = $sRaw + 2;
                    $sMake = $aShift['make'];
                    $sModel = $aShift['model1'];

                    if ($aBookmark['make'] != $aShift['make'])
                    {
                        $sBookmark = $oCatalog->create_bookmark($aShift['make'], sprintf('parent=%d', $sParent));
                        $aBookmark['make'] = $aShift['make'];
                        $aBookmark['model'] = '';
                        $aBookmark['current'] = $sBookmark;
                    }

                    if ($aBookmark['model'] != $aShift['model1'])
                    {
                        $aBookmark['model'] = $aShift['model1'];
                        $oCatalog->create_bookmark($aShift['model1'], sprintf('parent=%d', $aBookmark['current']));
                        $aVehicle[] = ['make' => $aBookmark['make'], 'model' => $aBookmark['model'], 'page' => $this->aOption['pagination']];
                    }
                }
            }

            if ($aShift['model1'] != $sModel)
            {
                if ($sRaw >= 69) {
                    $sData = false;
                }

                if ($sData)
                {
                    for ($sCol = 1; $sCol <= 8; $sCol ++)
                    {
                        $sColor = (($sCol == 1) || ($sCol == 7)) ? $this->aOption['colors']['back']: $this->aOption['colors']['white'];
                        $sOption = 'colwidth=%s rowheight=%s fittextline={font=%s fontsize=8 fitmethod=auto position={left center}} margin=2 matchbox={fillcolor=%s}';
                        $sOption = sprintf($sOption, $aPoint[sprintf('cellWidth%d', $sCol)], $aPoint['cellHeight'], $this->aOption['font']['arial_bd'], $sColor);
                        $sResult = $oCatalog->addTableCell($sResult, $sCol, $sRow, ($sCol == 1) ? $aShift['model1'] : '', $sOption);
                    }

                    $sModel = $aShift['model1'];
                    if ($aBookmark['model'] != $aShift['model1'])
                    {
                        $aBookmark['model'] = $aShift['model1'];
                        $oCatalog->create_bookmark($aShift['model1'], sprintf('parent=%d', $aBookmark['current']));
                        $aVehicle[] = ['make' => $aBookmark['make'],'model' => $aBookmark['model'], 'page' => $this->aOption['pagination']];
                    }

                    $sRow ++;
                    $sRaw ++;
                }
            }

            // 填充单元格
            $sFirst = true;
            $sCell = $sData;
            $sCount = count($aShift['value']);
            while ($sCell)
            {
                $sStart = $sFirst ? 1 : 2;
                $aData = array_shift($aShift['value']);
                for ($sCol = $sStart; $sCol <= 8; $sCol ++)
                {
                    $sValue = '';
                    $sOption = '';
                    switch ($sCol)
                    {
                        case 1:
                            // 需要计算rowspan
                            $sFirst = false;
                            $sValue = $aShift['model2'];
                            $sOption = 'colwidth=%s rowheight=%s rowspan=%d fittextline={font=%s fontsize=7 fitmethod=auto position={left top}} margin=2 matchbox={fillcolor=%s}';
                            $sRowspan = (($sCount + $sRaw) > 70) ? (70 - $sRaw) + 1 : $sCount;
                            if ($sRowspan <= 0) {
                                dd($sRowspan);
                            }
                            $sOption = sprintf($sOption, $aPoint[sprintf('cellWidth%d', $sCol)], $aPoint['cellHeight'] * $sRowspan, $sRowspan, $this->aOption['font']['arial'], $this->aOption['colors']['back']);
                            break;

                        case 2:
                            $sValue = $aData['col1'];
                            $sOption = 'colwidth=%s rowheight=%s fittextline={font=%s fontsize=7 fitmethod=auto position={left center}} margin=2';
                            $sOption = sprintf($sOption, $aPoint[sprintf('cellWidth%d', $sCol)], $aPoint['cellHeight'], $this->aOption['font']['arial']);
                            break;

                        case 3:
                            $sValue = $aData['col2'];
                            $sOption = 'colwidth=%s rowheight=%s fittextline={font=%s fontsize=7 fitmethod=auto position={left center}} margin=2';
                            $sOption = sprintf($sOption, $aPoint[sprintf('cellWidth%d', $sCol)], $aPoint['cellHeight'], $this->aOption['font']['arial']);
                            break;

                        case 4:
                            $sValue = $aData['col3'];
                            $sOption = 'colwidth=%s rowheight=%s fittextline={font=%s fontsize=7 fitmethod=auto position={left center}} margin=2';
                            $sOption = sprintf($sOption, $aPoint[sprintf('cellWidth%d', $sCol)], $aPoint['cellHeight'], $this->aOption['font']['arial']);
                            break;

                        case 5:
                            $sValue = $aData['col4'];
                            $sOption = 'colwidth=%s rowheight=%s fittextline={font=%s fontsize=7 fitmethod=auto position={left center}} margin=2';
                            $sOption = sprintf($sOption, $aPoint[sprintf('cellWidth%d', $sCol)], $aPoint['cellHeight'], $this->aOption['font']['arial']);
                            break;

                        case 6:
                            $sValue = $aData['col5'];
                            $sOption = 'colwidth=%s rowheight=%s fittextline={font=%s fontsize=7 fitmethod=auto position={left center}} margin=2';
                            $sOption = sprintf($sOption, $aPoint[sprintf('cellWidth%d', $sCol)], $aPoint['cellHeight'], $this->aOption['font']['arial']);
                            break;

                        case 7:
                            $sValue = $aData['col6'];
                            $sOption = 'colwidth=%s rowheight=%s fittextline={font=%s fontsize=7 fitmethod=auto position={left center}} margin=2 matchbox={fillcolor=%s}';
                            $sOption = sprintf($sOption, $aPoint[sprintf('cellWidth%d', $sCol)], $aPoint['cellHeight'], $this->aOption['font']['arial_bd'], $this->aOption['colors']['back']);
                            break;

                        case 8:
                            $sValue = $aData['col7'];
                            $sOption = 'colwidth=%s rowheight=%s fittextline={font=%s fontsize=7 fitmethod=auto position={left center}} margin=2';
                            $sOption = sprintf($sOption, $aPoint[sprintf('cellWidth%d', $sCol)], $aPoint['cellHeight'], $this->aOption['font']['arial']);
                            break;
                    }

                    $sResult = $oCatalog->addTableCell($sResult, $sCol, $sRow, $sValue, $sOption);
                }

                $sRow ++;
                $sRaw ++;
                if (!$aShift['value'] || ($sRaw > 70)) {
                    $sCell = false;
                }
            }

            // 页面结束
            if (($sRaw >= 70) || !$aValue || !$sData)
            {
                // 如当前弹出数据还有剩余, 插回去
                if ($aShift['value']) {
                    array_unshift($aValue, $aShift);
                }

                $sOption = 'header=0 rowheightdefault=auto stroke={
                        {line=frame linewidth=1 strokecolor=%s} 
                        {line=vert1 linewidth=1 strokecolor=%s}
                        {line=vert5 linewidth=1 strokecolor=%s}
                        {line=hor1 linewidth=1 strokecolor=%s}
                        {line=other linewidth=0.5 strokecolor=%s}
                    }';
                $sOption = sprintf($sOption, $this->aOption['colors']['line'], $this->aOption['colors']['line'], $this->aOption['colors']['line'], $this->aOption['colors']['line'], $this->aOption['colors']['black']);
                $sResult = $oCatalog->fit_table($sResult, $this->aOption['point']['x1'], $this->aOption['point']['y1'], $this->aOption['point']['x2'], $this->aOption['point']['y2'], $sOption);

                $oCatalog = $this->pagination($oCatalog, $this->aOption['pagination']);
                $oCatalog->end_page_ext('');

                $sRow = 1;
                $sRaw = 1;
                $sMake = '';
                $sModel = '';
                $this->aOption['pagination'] ++;
                if (!$aValue) {
                    $sWhile = false;
                }
            }
        }
        return $sBuffer ? ['vehicle' => $aVehicle, 'pagination' => $this->aOption['pagination'] - 1] : $oCatalog;
    }

    /**
     * 驱动轴车型应用
     *
     * @param PDFlib $oCatalog
     * @param array $aValue  数据
     * @param false $sBuffer 是否只返回车型索引页数据 和 车型应用页页码
     *
     * @example
     * [
     *      'style' => 'modelGuideByDrive', // 版式
     *      'value' => [
     *          [
     *              'make' => 'ACURA',
     *              'model1' => 'MDX',
     *              'model2' => '1966-1970',
     *              'remark' => "Quattro ALL (4A, C4) \nWith Sport sus.\nExc. S4",
     *              'value' => [
     *                  ['col1'=> '1990.12-1994.07', 'col2' => '7AT', 'col3'=> 'Front', 'col4' => 'AWD Engine CJSB', 'col5' => 'AWD Engine AAR (12.90-.)', 'col6' => 'Mounting,Radiator', 'col7' => '512205']
     *                  // ...
     *              ]
     *          ],
     *          // ....
     *      ]
     * ]
     *
     * @return array|PDFlib
     */
    public function modelGuideByDrive(PDFlib $oCatalog, array $aValue, bool $sBuffer = false)
    {
        $aPoint = [
            'cellWidth' => $this->aOption['point']['x2'] - $this->aOption['point']['x1'],
            'cellWidth1' => 108, // 车型列宽度
            'cellWidth2' => 51, // 年份列宽度
            'cellWidth3' => 29, // 变速器列
            'cellWidth4' => 71, //
            'cellWidth5' => 85, //
            'cellWidth6' => 85, //
            'cellWidth7' => 65, //
            'cellWidth8' => 31, //
            'cellHeight' => 11, // 表格高度
            'car' => sprintf('%s/image/%s/wheelCar.png', $this->aOption['resources'], $this->aOption['color']),
            'year' => sprintf('%s/image/%s/WaterPumpYear.png', $this->aOption['resources'], $this->aOption['color']),
            'product' => sprintf('%s/image/%s/8.png', $this->aOption['resources'], $this->aOption['color']),
        ];
        
        // 内容页面
        $sRow = 1;
        $sRaw = 1;
        $sMake = '';
        $sModel = '';
        $sData = true;
        $sWhile = true;
        
        $sParent = 0;
        $sResult = 0;
        $aVehicle = [];
        $sRemark = $aValue['remark'] ?? '';
        $aValue = $aValue['value'];
        $aBookmark = ['make' => '', 'model' => '', 'current' => 0];
        $aMatch = [1 => '', 'YEAR', 'TRANSM.', 'FITTING POSITION', 'BODY STYLE & DRIVE TYPE & ENGINE', 'REMARKS', 'PRODUCT', $this->aOption['gTitle']];
        while ($sWhile)
        {
            // 页面开始
            if ($sRow == 1)
            {
                $sData = true;
                $sResult = 0;
                $oCatalog->begin_page_ext(0, 0, 'width=a4.width height=a4.height');
                // 分部书签
                if (!$sParent && $sRemark) {
                    $sParent = $oCatalog->create_bookmark($sRemark, sprintf('parent=%d', 0));
                }
                
                for ($sCol = 1; $sCol <= 8; $sCol ++)
                {
                    switch ($sCol)
                    {
                        case 1:
                            $oImage = $oCatalog->loadImage('auto', $aPoint['car'], '');
                            $sOption = 'colwidth=%s rowheight=%s image=%s fitimage={position={center}} fittextline={font=%s fitmethod=auto fontsize=9} matchbox={fillcolor=%s} margin=1.5';
                            $sOption = sprintf($sOption, $aPoint[sprintf('cellWidth%d', $sCol)], $aPoint['cellHeight'] * 4, $oImage, $this->aOption['font']['arial_bd'], $this->aOption['colors']['back']);
                            break;
                        
                        case 2:
                        case 7:
                            $oImage = $oCatalog->loadImage('auto', $aPoint[($sCol == 2) ? 'year' : 'product'], '');
                            $sOption = 'colwidth=%s rowheight=%s image=%s fitimage={position={center bottom}} fittextline={font=%s fontsize=7 fitmethod=auto fillcolor=%s position={center bottom}} margin=5';
                            $sOption = sprintf($sOption, $aPoint[sprintf('cellWidth%d', $sCol)], $aPoint['cellHeight'] * 4, $oImage, $this->aOption['font']['arial_bd'], $this->aOption['colors']['font']);
                            break;
                        
                        case 3:
                        case 4:
                        case 5:
                        case 6:
                            $sOption = 'colwidth=%s rowheight=%s fittextline={font=%s fontsize=%d fitmethod=auto fillcolor=%s} margin=1.5';
                            $sOption = sprintf($sOption, $aPoint[sprintf('cellWidth%d', $sCol)], $aPoint['cellHeight'] * 4, $this->aOption['font']['arial_bd'], ($sCol == 3) ? 5 : 7, $this->aOption['colors']['font']);
                            break;
                        
                        case 8:
                            $sOption = 'colwidth=%s rowheight=%s fittextline={font=%s fontsize=7 fitmethod=auto fillcolor=%s} matchbox={fillcolor=%s} margin=1.5';
                            $sOption = sprintf($sOption, $aPoint[sprintf('cellWidth%d', $sCol)], $aPoint['cellHeight'] * 4, $this->aOption['font']['arial_bd'], $this->aOption['colors']['font'], $this->aOption['colors']['back']);
                            break;
                    }
                    
                    $sResult = $oCatalog->addTableCell($sResult, $sCol, $sRow, $aMatch[$sCol], $sOption);
                }
                $sRow ++;
                $sRaw = $sRaw + 4;
            }
            $aShift = array_shift($aValue);
            
            // 车型列
            if ($sMake != $aShift['make'])
            {
                if ($sRaw >= 68) {
                    $sData = false;
                }
                
                if ($sData)
                {
                    foreach ([1, 2, 8] as $sCol)
                    {
                        $sOption = '';
                        switch ($sCol)
                        {
                            case 1:
                                $sChild = 0;
                                $sOption = 'colwidth=%s rowheight=%s fittextline={font=%s fontsize=10 fitmethod=auto position={left center}} matchbox={fillcolor=%s} margin=2';
                                $sOption = sprintf($sOption, $aPoint['cellWidth1'], $aPoint['cellHeight'], $this->aOption['font']['arial_bd'], $this->aOption['colors']['back']);
                                $sChild = $oCatalog->addTableCell($sChild, 1, 1, $aShift['make'], $sOption);
    
                                $sOption = 'colwidth=%s rowheight=%s fittextline={font=%s fontsize=8 fitmethod=auto position={left center}} matchbox={fillcolor=%s} margin=2';
                                $sOption = sprintf($sOption, $aPoint['cellWidth1'], $aPoint['cellHeight'], $this->aOption['font']['arial_bd'], $this->aOption['colors']['back']);
                                $sChild = $oCatalog->addTableCell($sChild, 1, 2, $aShift['model1'], $sOption);
    
                                $sOption = 'header=0 rowheightdefault=auto stroke={{line=other linewidth=0}}';
                                $sChild = $oCatalog->fit_table(
                                    $sChild,
                                    $this->aOption['point']['x1'],
                                    $this->aOption['point']['y2'] - ($sRaw + 1) * $aPoint['cellHeight'],
                                    $this->aOption['point']['x1'] + $aPoint['cellWidth1'],
                                    $this->aOption['point']['y2'] - ($sRaw - 1) * $aPoint['cellHeight'],
                                    $sOption
                                );
    
                                $sOption = 'colwidth=%s rowheight=%s';
                                $sOption = sprintf($sOption, $aPoint[sprintf('cellWidth%d', $sCol)], $aPoint['cellHeight'] * 2);
                                break;
                            
                            case 2:
                                $sWidth = $aPoint['cellWidth'] - $aPoint['cellWidth1'] - $aPoint['cellWidth8'];
                                $sOption = 'colwidth=%s rowheight=%s fittextline={font=%s fontsize=8 fitmethod=auto} colspan=6';
                                $sOption = sprintf($sOption, $sWidth, $aPoint['cellHeight'] * 2, $this->aOption['font']['arial_bd']);
                                break;
                            
                            case 8:
                                $sOption = 'colwidth=%s rowheight=%s fittextline={font=%s fontsize=14 fitmethod=auto position={left center}} margin=2 matchbox={fillcolor=%s}';
                                $sOption = sprintf($sOption, $aPoint[sprintf('cellWidth%d', $sCol)], $aPoint['cellHeight'] * 2, $this->aOption['font']['arial_bd'], $this->aOption['colors']['back']);
                                break;
                        }
                        
                        $sResult = $oCatalog->addTableCell($sResult, $sCol, $sRow, '', $sOption);
                    }
                    
                    $sRow ++;
                    $sRaw = $sRaw + 2;
                    $sMake = $aShift['make'];
                    $sModel = $aShift['model1'];
                    if ($aBookmark['make'] != $aShift['make'])
                    {
                        $sBookmark = $oCatalog->create_bookmark($aShift['make'], sprintf('parent=%d', $sParent));

                        $aBookmark['make'] = $aShift['make'];
                        $aBookmark['model'] = '';
                        $aBookmark['current'] = $sBookmark;
                    }

                    if ($aBookmark['model'] != $aShift['model1'])
                    {
                        $aBookmark['model'] = $aShift['model1'];
                        $oCatalog->create_bookmark($aShift['model1'], sprintf('parent=%d', $aBookmark['current']));
                        $aVehicle[] = ['make' => $aBookmark['make'], 'model' => $aBookmark['model'], 'page' => $this->aOption['pagination']];
                    }
                }
            }

            if ($sModel != $aShift['model1'])
            {
                if ($sRaw >= 69) {
                    $sData = false;
                }
                
                if ($sData)
                {
                    foreach ([1, 2, 8] as $sCol)
                    {
                        $sOption = '';
                        switch ($sCol)
                        {
                            case 1:
                                $sOption = 'colwidth=%s rowheight=%s fittextline={font=%s fontsize=8 fitmethod=auto position={left center}} margin=2 matchbox={fillcolor=%s}';
                                $sOption = sprintf($sOption, $aPoint[sprintf('cellWidth%d', $sCol)], $aPoint['cellHeight'], $this->aOption['font']['arial_bd'], $this->aOption['colors']['back']);
                                break;
                            
                            case 2:
                                $sWidth = $aPoint['cellWidth'] - $aPoint['cellWidth1'] - $aPoint['cellWidth8'];
                                $sOption = 'colwidth=%s rowheight=%s fittextline={font=%s fitmethod=auto fontsize=8} colspan=6';
                                $sOption = sprintf($sOption, $sWidth, $aPoint['cellHeight'], $this->aOption['font']['arial_bd']);
                                break;
                            
                            case 8:
                                $sOption = 'colwidth=%s rowheight=%s fittextline={font=%s fitmethod=auto fontsize=14 position={left center}} margin=2 matchbox={fillcolor=%s}';
                                $sOption = sprintf($sOption, $aPoint[sprintf('cellWidth%d', $sCol)], $aPoint['cellHeight'], $this->aOption['font']['arial_bd'], $this->aOption['colors']['back']);
                                break;
                        }
                        
                        $sResult = $oCatalog->addTableCell($sResult, $sCol, $sRow, ($sCol == 1) ? $aShift['model1'] : '', $sOption);
                    }

                    $sModel = $aShift['model1'];
                    if ($aShift['model1'] != $aBookmark['model'])
                    {
                        $aBookmark['model'] = $aShift['model1'];
                        $oCatalog->create_bookmark($aShift['model1'], sprintf('parent=%d', $aBookmark['current']));
                        $aVehicle[] = ['make' => $aBookmark['make'],'model' => $aBookmark['model'], 'page' => $this->aOption['pagination']];
                    }

                    $sRow ++;
                    $sRaw ++;
                }
            }
            
            // 填充单元格
            $sFirst = true;
            $sCell = $sData;
            $sCount = count($aShift['value']);
            while ($sCell)
            {
                $sStart = $sFirst ? 1 : 2;
                $aData = array_shift($aShift['value']);
                for ($sCol = $sStart; $sCol <= 8; $sCol ++)
                {
                    $sValue = '';
                    $sOption = '';
                    switch ($sCol)
                    {
                        case 1:
                            // 需要计算rowspan
                            $sFirst = false;
                            $sValue = $aShift['model2'];
                            $sRowspan = (($sCount + $sRaw) > 70) ? (70 - $sRaw) + 1 : $sCount;
                            $sOption = 'colwidth=%s rowheight=%s rowspan=%d fittextline={font=%s fontsize=7 fitmethod=auto fitmethod=auto position={left %s}} margin=2 matchbox={fillcolor=%s}';
                            $sOption = sprintf($sOption, $aPoint[sprintf('cellWidth%d', $sCol)], $aPoint['cellHeight'] * $sRowspan, $sRowspan, $this->aOption['font']['arial'], ($sRowspan > 1) ? 'top' : 'center', $this->aOption['colors']['back']);
                            break;
                        
                        case 2:
                            $sValue = $aData['col1'];
                            $sOption = 'colwidth=%s rowheight=%s fittextline={font=%s fontsize=7 fitmethod=auto fitmethod=auto position={left center}} margin=2';
                            $sOption = sprintf($sOption, $aPoint[sprintf('cellWidth%d', $sCol)], $aPoint['cellHeight'], $this->aOption['font']['arial']);
                            break;
                        
                        case 3:
                            $sValue = $aData['col2'];
                            $sOption = 'colwidth=%s rowheight=%s fittextline={font=%s fontsize=7 fitmethod=auto fitmethod=auto position={left center}} margin=2';
                            $sOption = sprintf($sOption, $aPoint[sprintf('cellWidth%d', $sCol)], $aPoint['cellHeight'], $this->aOption['font']['arial']);
                            break;
                        
                        case 4:
                            $sValue = $aData['col3'];
                            $sOption = 'colwidth=%s rowheight=%s fittextline={font=%s fontsize=7 fitmethod=auto fitmethod=auto position={left center}} margin=2';
                            $sOption = sprintf($sOption, $aPoint[sprintf('cellWidth%d', $sCol)], $aPoint['cellHeight'], $this->aOption['font']['arial']);
                            break;
                        
                        case 5:
                            $sValue = $aData['col4'];
                            $sOption = 'colwidth=%s rowheight=%s fittextline={font=%s fontsize=7 fitmethod=auto fitmethod=auto position={left center}} margin=2';
                            $sOption = sprintf($sOption, $aPoint[sprintf('cellWidth%d', $sCol)], $aPoint['cellHeight'], $this->aOption['font']['arial']);
                            break;
                        
                        case 6:
                            $sValue = $aData['col5'];
                            $sOption = 'colwidth=%s rowheight=%s fittextline={font=%s fontsize=7 fitmethod=auto fitmethod=auto position={left center}} margin=2';
                            $sOption = sprintf($sOption, $aPoint[sprintf('cellWidth%d', $sCol)], $aPoint['cellHeight'], $this->aOption['font']['arial']);
                            break;
                        
                        case 7:
                            $sValue = $aData['col6'];
                            $sOption = 'colwidth=%s rowheight=%s fittextline={font=%s fontsize=7 fitmethod=auto fitmethod=auto position={left center}} margin=2';
                            $sOption = sprintf($sOption, $aPoint[sprintf('cellWidth%d', $sCol)], $aPoint['cellHeight'], $this->aOption['font']['arial']);
                            break;
                        
                        case 8:
                            $sValue = $aData['col7'];
                            $sOption = 'colwidth=%s rowheight=%s fittextline={font=%s fontsize=7 fitmethod=auto fitmethod=auto position={left center}} margin=2 matchbox={fillcolor=%s}';
                            $sOption = sprintf($sOption, $aPoint[sprintf('cellWidth%d', $sCol)], $aPoint['cellHeight'], $this->aOption['font']['arial'], $this->aOption['colors']['back']);
                            break;
                    }
                    
                    $sResult = $oCatalog->addTableCell($sResult, $sCol, $sRow, $sValue, $sOption);
                }
                
                $sRow ++;
                $sRaw ++;
                if (!$aShift['value'] || ($sRaw > 70)) {
                    $sCell = false;
                }
            }
            
            // 页面结束
            if (($sRaw >= 70) || !$aValue || !$sData)
            {
                // 如当前弹出数据还有剩余, 插回去
                if ($aShift['value']) {
                    array_unshift($aValue, $aShift);
                }
                
                $sOption = 'header=0 rowheightdefault=auto stroke={
                        {line=frame linewidth=1 strokecolor=%s} 
                        {line=vert1 linewidth=1 strokecolor=%s}
                        {line=vert7 linewidth=1 strokecolor=%s}
                        {line=hor1 linewidth=1 strokecolor=%s}
                        {line=other linewidth=0.1}
                    }';
                $sOption = sprintf($sOption, $this->aOption['colors']['line'], $this->aOption['colors']['line'], $this->aOption['colors']['line'], $this->aOption['colors']['line']);
                $sResult = $oCatalog->fit_table($sResult, $this->aOption['point']['x1'], $this->aOption['point']['y1'], $this->aOption['point']['x2'], $this->aOption['point']['y2'], $sOption);
                
                $oCatalog = $this->pagination($oCatalog, $this->aOption['pagination']);
                $oCatalog->end_page_ext('');
                $this->aOption['pagination'] ++;
                
                $sRow = 1;
                $sRaw = 1;
                $sMake = '';
                $sModel = '';
                if (!$aValue) {
                    $sWhile = false;
                }
            }
        }

        return $sBuffer ? ['vehicle' => $aVehicle, 'pagination' => $this->aOption['pagination'] - 1] : $oCatalog;
    }
    
    /**
     * 轴承车型应用
     *
     * @param PDFlib $oCatalog
     * @param array $aValue  数据
     * @param false $sBuffer 是否只返回车型索引页数据 和 车型应用页页码
     *
     * @example
     * [
     *      'style' => 'modelGuideByBearing', // 版式
     *      'value' => [
     *          [
     *              'make' => 'ACURA',
     *              'model1' => 'MDX',
     *              'model2' => '1966-1970',
     *              'remark' => "Quattro ALL (4A, C4) \nWith Sport sus.\nExc. S4",
     *              'value' => [
     *                  ['col1' => '1990.12-1994.07', 'col2' => 'Hatchback Engine AR33503/AR38501', 'col3' => '9710012'],
     *                  // ...
     *              ]
     *          ],
     *          // ....
     *      ]
     * ]
     *
     * @return array|PDFlib
     */
    public function modelGuideByBearing(PDFlib $oCatalog, array $aValue, bool $sBuffer = false)
    {
        $aPoint = [
            'cellWidth' => $this->aOption['point']['x2'] - $this->aOption['point']['x1'],
            'cellWidth1' => 158, // 车型列宽度
            'cellWidth2' => 70, // 年份列宽度
            'cellWidth3' => 142, //
            'cellWidth4' => 85, //
            'cellWidth5' => 70, //
            
            'cellHeight' => 11, // 表格高度
            'car' => sprintf('%s/image/%s/wheelCar.png', $this->aOption['resources'], $this->aOption['color']),
            'year' => sprintf('%s/image/%s/WaterPumpYear.png', $this->aOption['resources'], $this->aOption['color']),
        ];
        
        // 内容页面
        $sRow = 1;
        $sRaw = 1;
        $sMake = '';
        $sModel = '';
        $sData = true;
        $sWhile = true;
        
        $sParent = 0;
        $sResult = 0;
        $aVehicle = [];
        $sRemark = $aValue['remark'] ?? '';
        $aValue = $aValue['value'];
        $aBookmark = ['make' => '', 'model' => '', 'current' => 0];
        $aMatch = [1 => '', 'YEAR', 'BODY STYLE & DRIVE TYPE & ENGINE', 'PRODUCT', $this->aOption['gTitle']];
        while ($sWhile)
        {
            // 页面开始
            if ($sRow == 1)
            {
                $sData = true;
                $sResult = 0;
                $oCatalog->begin_page_ext(0, 0, 'width=a4.width height=a4.height');
                // 分部书签
                if (!$sParent && $sRemark) {
                    $sParent = $oCatalog->create_bookmark($sRemark, sprintf('parent=%d', 0));
                }

                $sHeader = 0;
                for ($sCol = 1; $sCol <= 5; $sCol ++)
                {
                    switch ($sCol)
                    {
                        case 1:
                            $oImage = $oCatalog->loadImage('auto', $aPoint['car'], '');
                            $sOption = 'colwidth=%s rowheight=%s image=%s fitimage={position={center}} fittextline={font=%s fontsize=9 fitmethod=auto} matchbox={fillcolor=%s}';
                            $sOption = sprintf($sOption, $aPoint[sprintf('cellWidth%d', $sCol)], $aPoint['cellHeight'] * 4, $oImage, $this->aOption['font']['arial_bd'], $this->aOption['colors']['back']);
                            break;
                        
                        case 2:
                            $oImage = $oCatalog->loadImage('auto', $aPoint[($sCol == 2) ? 'year' : 'product'], '');
                            $sOption = 'colwidth=%s rowheight=%s image=%s fitimage={position={center bottom}} fittextline={font=%s fontsize=9 fitmethod=auto fillcolor=%s position={center bottom}} margin=5';
                            $sOption = sprintf($sOption, $aPoint[sprintf('cellWidth%d', $sCol)], $aPoint['cellHeight'] * 4, $oImage, $this->aOption['font']['arial_bd'], $this->aOption['colors']['font']);
                            break;
                        
                        case 5:
                            $sOption = 'colwidth=%s rowheight=%s fittextline={font=%s fontsize=9 fitmethod=auto fillcolor=%s} matchbox={fillcolor=%s}';
                            $sOption = sprintf($sOption, $aPoint[sprintf('cellWidth%d', $sCol)], $aPoint['cellHeight'] * 4, $this->aOption['font']['arial_bd'], $this->aOption['colors']['font'], $this->aOption['colors']['back']);
                            break;
                            
                        default:
                            $sOption = 'colwidth=%s rowheight=%s fittextline={font=%s fontsize=9 fitmethod=auto fillcolor=%s} margin=1.5';
                            $sOption = sprintf($sOption, $aPoint[sprintf('cellWidth%d', $sCol)], $aPoint['cellHeight'] * 4, $this->aOption['font']['arial_bd'], $this->aOption['colors']['font']);
                            break;
                    }
                    $sHeader = $oCatalog->addTableCell($sHeader, $sCol, $sRow, $aMatch[$sCol], $sOption);
                }
                $sOption = 'header=0 rowheightdefault=auto stroke={{line=other linewidth=1 strokecolor=%s}}';
                $sOption = sprintf($sOption, $this->aOption['colors']['line']);
                $oCatalog->fit_table($sHeader, $this->aOption['point']['x1'], $this->aOption['point']['y2'] - $aPoint['cellHeight'] * 4, $this->aOption['point']['x2'], $this->aOption['point']['y2'], $sOption);

                $sOption = 'rowheight=%s fittextline={font=%s fontsize=7 fillcolor=%s fitmethod=auto} colspan=5';
                $sOption = sprintf($sOption, $aPoint['cellHeight'] * 4, $this->aOption['font']['arial_bd'], $this->aOption['colors']['font']);
                $sResult = $oCatalog->addTableCell($sResult, 1, $sRow, '', $sOption);

                $sRow ++;
                $sRaw = $sRaw + 4;
            }
            $aShift = array_shift($aValue);
            
            // 车型列
            if ($sMake != $aShift['make'])
            {
                if ($sRaw >= 68) {
                    $sData = false;
                }
                
                if ($sData)
                {
                    $aCol = [1, 2, 5];
                    foreach ($aCol as $sCol)
                    {
                        switch ($sCol)
                        {
                            case 1:
                                $sChild = 0;
                                $sOption = 'colwidth=%s rowheight=%s fittextline={font=%s fontsize=10 fitmethod=auto position={left center}} matchbox={fillcolor=%s} margin=2';
                                $sOption = sprintf($sOption, $aPoint['cellWidth1'], $aPoint['cellHeight'], $this->aOption['font']['arial_bd'], $this->aOption['colors']['back']);
                                $sChild = $oCatalog->addTableCell($sChild, 1, 1, $aShift['make'], $sOption);
    
                                $sOption = 'colwidth=%s rowheight=%s fittextline={font=%s fontsize=8 fitmethod=auto position={left center}} matchbox={fillcolor=%s} margin=2';
                                $sOption = sprintf($sOption, $aPoint['cellWidth1'], $aPoint['cellHeight'], $this->aOption['font']['arial_bd'], $this->aOption['colors']['back']);
                                $sChild = $oCatalog->addTableCell($sChild, 1, 2, $aShift['model1'], $sOption);
    
                                $sOption = 'header=0 rowheightdefault=auto stroke={{line=other linewidth=0}}';
                                $sChild = $oCatalog->fit_table(
                                    $sChild,
                                    $this->aOption['point']['x1'],
                                    $this->aOption['point']['y2'] - ($sRaw + 1) * $aPoint['cellHeight'],
                                    $this->aOption['point']['x1'] + $aPoint['cellWidth1'],
                                    $this->aOption['point']['y2'] - ($sRaw - 1) * $aPoint['cellHeight'],
                                    $sOption
                                );
    
                                $sOption = 'colwidth=%s rowheight=%s';
                                $sOption = sprintf($sOption, $aPoint[sprintf('cellWidth%d', $sCol)], $aPoint['cellHeight'] * 2);
                                break;
                            
                            case 5:
                                $sOption = 'colwidth=%s rowheight=%s fittextline={font=%s fontsize=14 fitmethod=auto position={left center}} margin=1.5 matchbox={fillcolor=%s}';
                                $sOption = sprintf($sOption, $aPoint[sprintf('cellWidth%d', $sCol)], $aPoint['cellHeight'] * 2, $this->aOption['font']['arial_bd'], $this->aOption['colors']['back']);
                                break;
                            
                            default:
                                $sOption = 'colwidth=%s rowheight=%s colspan=3 fittextline={font=%s fontsize=8 fitmethod=auto}';
                                $sOption = sprintf($sOption, ($aPoint['cellWidth2'] + $aPoint['cellWidth3'] + $aPoint['cellWidth4']), $aPoint['cellHeight'] * 2, $this->aOption['font']['arial_bd']);
                                break;
                        }
                        
                        $sResult = $oCatalog->addTableCell($sResult, $sCol, $sRow, '', $sOption);
                    }
                    
                    $sRow ++;
                    $sRaw = $sRaw + 2;
                    $sMake = $aShift['make'];
                    $sModel = $aShift['model1'];

                    if ($aBookmark['make'] != $aShift['make'])
                    {
                        $sBookmark = $oCatalog->create_bookmark($aShift['make'], sprintf('parent=%d', $sParent));

                        $aBookmark['make'] = $aShift['make'];
                        $aBookmark['model'] = '';
                        $aBookmark['current'] = $sBookmark;
                    }

                    if ($aBookmark['model'] != $aShift['model1'])
                    {
                        $aBookmark['model'] = $aShift['model1'];
                        $oCatalog->create_bookmark($aShift['model1'], sprintf('parent=%d', $aBookmark['current']));
                        $aVehicle[] = ['make' => $aBookmark['make'], 'model' => $aBookmark['model'], 'page' => $this->aOption['pagination']];
                    }
                }
            }
            
            if ($sModel != $aShift['model1'])
            {
                if ($sRaw >= 69) {
                    $sData = false;
                }
                
                if ($sData)
                {
                    $aMod = [1, 2, 5];
                    foreach ($aMod as $sCol)
                    {
                        switch ($sCol)
                        {
                            case 1:
                                $sOption = 'colwidth=%s rowheight=%s fittextline={font=%s fontsize=8 fitmethod=auto position={left center}} margin=1.5 matchbox={fillcolor=%s}';
                                $sOption = sprintf($sOption, $aPoint[sprintf('cellWidth%d', $sCol)], $aPoint['cellHeight'], $this->aOption['font']['arial_bd'], $this->aOption['colors']['back']);
                                break;
                            
                            case 5:
                                $sOption = 'colwidth=%s rowheight=%s fittextline={font=%s fontsize=14 fitmethod=auto position={left center}} margin=1.5 matchbox={fillcolor=%s}';
                                $sOption = sprintf($sOption, $aPoint[sprintf('cellWidth%d', $sCol)], $aPoint['cellHeight'], $this->aOption['font']['arial_bd'], $this->aOption['colors']['back']);
                                break;
                            
                            default:
                                $sOption = 'colwidth=%s rowheight=%s fittextline={font=%s fontsize=8 fitmethod=auto} colspan=3';
                                $sOption = sprintf($sOption, ($aPoint['cellWidth2']+$aPoint['cellWidth3']+$aPoint['cellWidth4']), $aPoint['cellHeight'] * 2, $this->aOption['font']['arial_bd']);
                                break;
                        }
                        
                        $sResult = $oCatalog->addTableCell($sResult, $sCol, $sRow, ($sCol == 1) ? $aShift['model1'] : '', $sOption);
                    }
                    
                    $sModel = $aShift['model1'];
                    if ($aShift['model1'] != $aBookmark['model'])
                    {
                        $aBookmark['model'] = $aShift['model1'];
                        $oCatalog->create_bookmark($aShift['model1'], sprintf('parent=%d', $aBookmark['current']));
                        $aVehicle[] = ['make' => $aBookmark['make'],'model' => $aBookmark['model'], 'page' => $this->aOption['pagination']];
                    }
                    
                    $sRow ++;
                    $sRaw ++;
                }
            }
            
            // 填充单元格
            $sFirst = true;
            $sCell = $sData;
            $sCount = count($aShift['value']);
            while ($sCell)
            {
                $sStart = $sFirst ? 1 : 2;
                $aData = array_shift($aShift['value']);
                for ($sCol = $sStart; $sCol <= 5; $sCol ++)
                {
                    $sValue = '';
                    $sOption = '';
                    switch ($sCol)
                    {
                        case 1:
                            // 需要计算rowspan
                            $sFirst = false;
                            $sValue = $aShift['model2'];
                            $sRowspan = (($sCount + $sRaw) > 70) ? (70 - $sRaw) + 1 : $sCount;
                            $sOption = 'colwidth=%s rowheight=%s rowspan=%d fittextline={font=%s fontsize=8 fitmethod=auto position={left %s}} margin=1.5 matchbox={fillcolor=%s}';
                            $sOption = sprintf($sOption, $aPoint[sprintf('cellWidth%d', $sCol)], $aPoint['cellHeight'] * $sRowspan, $sRowspan, $this->aOption['font']['arial'],  ($sRowspan > 1) ? 'top' : 'center', $this->aOption['colors']['back']);
                            break;
                        
                        case 2:
                            $sValue = $aData['col1'];
                            $sOption = 'colwidth=%s rowheight=%s fittextline={font=%s fontsize=8 fitmethod=auto position={left center}} margin=1.5';
                            $sOption = sprintf($sOption, $aPoint[sprintf('cellWidth%d', $sCol)], $aPoint['cellHeight'], $this->aOption['font']['arial']);
                            break;
                        
                        case 3:
                            $sValue = $aData['col2'];
                            $sOption = 'colwidth=%s rowheight=%s fittextline={font=%s fontsize=8 fitmethod=auto position={left center}} margin=1.5';
                            $sOption = sprintf($sOption, $aPoint[sprintf('cellWidth%d', $sCol)], $aPoint['cellHeight'], $this->aOption['font']['arial']);
                            break;
    
                        case 4:
                            $sValue = $aData['col3'];
                            $sOption = 'colwidth=%s rowheight=%s fittextline={font=%s fontsize=8 fitmethod=auto position={left center}} margin=1.5';
                            $sOption = sprintf($sOption, $aPoint[sprintf('cellWidth%d', $sCol)], $aPoint['cellHeight'], $this->aOption['font']['arial']);
                            break;
                        
                        case 5:
                            $sValue = $aData['col4'];
                            $sOption = 'colwidth=%s rowheight=%s fittextline={font=%s fontsize=8 fitmethod=auto position={left center}} margin=1.5 matchbox={fillcolor=%s}';
                            $sOption = sprintf($sOption, $aPoint[sprintf('cellWidth%d', $sCol)], $aPoint['cellHeight'], $this->aOption['font']['arial_bd'], $this->aOption['colors']['back']);
                            break;
                    }
                    
                    $sResult = $oCatalog->addTableCell($sResult, $sCol, $sRow, $sValue, $sOption);
                }
                
                $sRow ++;
                $sRaw ++;
                if (!$aShift['value'] || ($sRaw > 70)) {
                    $sCell = false;
                }
            }
            
            // 页面结束
            if (($sRaw >= 70) || !$aValue || !$sData)
            {
                // 如当前弹出数据还有剩余, 插回去
                if ($aShift['value']) {
                    array_unshift($aValue, $aShift);
                }
                
                $sOption = 'header=0 rowheightdefault=auto stroke={
                        {line=frame linewidth=1 strokecolor=%s}
                        {line=vert1 linewidth=1 strokecolor=%s}
                        {line=vert4 linewidth=1 strokecolor=%s}
                        {line=hor1 linewidth=1 strokecolor=%s}
                        {line=other linewidth=0.1}
                    }';
                $sOption = sprintf($sOption, $this->aOption['colors']['line'], $this->aOption['colors']['line'], $this->aOption['colors']['line'], $this->aOption['colors']['line']);
                $sResult = $oCatalog->fit_table($sResult, $this->aOption['point']['x1'], $this->aOption['point']['y1'], $this->aOption['point']['x2'], $this->aOption['point']['y2'], $sOption);
                
                $oCatalog = $this->pagination($oCatalog, $this->aOption['pagination']);
                $oCatalog->end_page_ext('');
                $this->aOption['pagination'] ++;
                
                $sRow = 1;
                $sRaw = 1;
                $sMake = '';
                $sModel = '';
                if (!$aValue) {
                    $sWhile = false;
                }
            }
        }
        
        return $sBuffer ? ['vehicle' => $aVehicle, 'pagination' => $this->aOption['pagination'] - 1] : $oCatalog;
    }
    
    /**
     * 照片排版1
     *
     * @param PDFlib $oCatalog
     * @param array $aValue  数据
     * @param false $sBuffer 是否只返回页码
     *
     * @example
     * [
     *      'style' => 'photoGuideByWheel', // 版式
     *      'title' => 'Hub Assemblies | BraKe Disc/Brake Drum | Drive Shaft | Bearing Kits', // 标题
     *      'value' => [
     *          // 图片使用绝对路径, 避免不必要的问题
     *          ['col1' => '9223001', 'col2' => '/home/wwwroot/picpath/picname.jpg'],
     *          ['col1' => '9223001', 'col2' => '/home/wwwroot/picpath/picname.jpg'],
     *          ...
     *      ],
     * ]
     *
     * @return int|PDFlib
     */
    public function photoGuideByWheel(PDFlib $oCatalog, array $aValue, bool $sBuffer = false)
    {
        $aPoint = [
            'x1' => 70, // 左2.5cm
            'x2' => 530, // 右2.3cm
            'y2' => 750,
            
            'headerY1' => 791,
            'headerY2' => 768,
            
            'cellWidth' => 213,
            'cellWidthOther' => 34,
            'cellHeight' => 116, // 表格高度
        ];
        $aTable = [
            1 => [
                'x1' => $aPoint['x1'],
                'y1' => $aPoint['y2'] - $aPoint['cellHeight'],
                'x2' => $aPoint['x1'] + $aPoint['cellWidth'],
                'y2' => $aPoint['y2'],
            ],
            
            2 => [
                'x1' => $aPoint['x1'] + $aPoint['cellWidth'] + $aPoint['cellWidthOther'],
                'y1' => $aPoint['y2'] - $aPoint['cellHeight'],
                'x2' => $aPoint['x1'] + 2 * $aPoint['cellWidth'] + $aPoint['cellWidthOther'],
                'y2' => $aPoint['y2'],
            ]
        ];
        
        $sTake = 12;
        $sBookmark = 0;
        $sTitle = $aValue['title'];
        $sRemark = $aValue['remark'] ?? '';
        $aValue = $aValue['value'];
        $sSkip = ceil(count($aValue) / $sTake);
        for ($sPage = 1; $sPage <= $sSkip; $sPage ++)
        {
            $oCatalog->begin_page_ext(0, 0, 'width=a4.width height=a4.height');
            if (!$sBookmark && $sRemark) {
                $sBookmark = $oCatalog->create_bookmark($sTitle.' '.$sRemark, sprintf('parent=%d', 0));
            }
            
            // 页头设置
            $sOption = 'fontname={font/arial_bd} embedding fontsize=16 encoding=unicode fillcolor=%s';
            $sOption = sprintf($sOption, $this->aOption['colors']['font']);
            $oCatalog->fit_textline($sTitle, $aPoint['x1'], $aPoint['headerY1'], $sOption);
            
            $sOption = 'fontname={font/arial} embedding fontsize=14 encoding=unicode fillcolor=%s';
            $sOption = sprintf($sOption, $this->aOption['colors']['font']);
            $oCatalog->fit_textline('Photo…………………………………………………………………………………', $aPoint['x1'], $aPoint['headerY2'], $sOption);
            
            for ($sRow = 1; $sRow <= 6; $sRow ++)
            {
                for ($sCol = 1; $sCol <= 2; $sCol ++)
                {
                    if (!$aValue) {
                        continue;
                    }
                    $aShift = array_shift($aValue);
                    
                    $sResult = 0;
                    $sOption = 'colwidth=%s rowheight=%s fittextline={font=%s fontsize=14 fitmethod=auto} matchbox={fillcolor=%s}';
                    $sOption = sprintf($sOption, $aPoint['cellWidth'], 28, $this->aOption['font']['arial_bd'], $this->aOption['colors']['back']);
                    $sResult = $oCatalog->addTableCell($sResult, 1, 1, $aShift['col1'], $sOption);
                    
                    $oImage = $oCatalog->loadImage('auto', $aShift['col2'], '');
                    $sOption = sprintf('colwidth=%s rowheight=%s image=%s fitimage={position={center}}', $aPoint['cellWidth'], 88, $oImage);
                    $sResult = $oCatalog->addTableCell($sResult, 1, 2, '', $sOption);
                    
                    // 生成表格
                    $sOption = 'header=0 rowheightdefault=auto stroke={{line=frame linewidth=1.5 strokecolor=%s}}';
                    $sOption = sprintf($sOption, $this->aOption['colors']['line']);
                    $oCatalog->fit_table(
                        $sResult,
                        $aTable[$sCol]['x1'],
                        $aTable[$sCol]['y1'] - ($sRow - 1) * $aPoint['cellHeight'],
                        $aTable[$sCol]['x2'],
                        $aTable[$sCol]['y2'] - ($sRow - 1) * $aPoint['cellHeight'],
                        $sOption
                    );
                }
            }
            
            $oCatalog = $this->pagination($oCatalog, $this->aOption['pagination']);
            $oCatalog->end_page_ext('');
            $this->aOption['pagination'] ++;
        }
        
        return $sBuffer ? ($this->aOption['pagination'] - 1) : $oCatalog;
    }
    
    /**
     * 照片排版2
     *
     * @param PDFlib $oCatalog
     * @param array $aValue  数据
     * @param false $sBuffer 是否只返回页码
     *
     * @example
     * [
     *      'style' => 'photoGuideByWaterPump', // 版式
     *      'title' => 'Water pump', // 标题
     *      'value' => [
     *          // 图片使用绝对路径, 避免不必要的问题
     *          ['col1' => '9223001', 'col2' => '/home/wwwroot/picpath/picname.jpg'],
     *          ['col1' => '9223001', 'col2' => '/home/wwwroot/picpath/picname.jpg'],
     *          ...
     *      ],
     * ]
     *
     * @return int|PDFlib
     */
    public function photoGuideByWaterPump(PDFlib $oCatalog, array $aValue, bool $sBuffer = false)
    {
        $aPoint = [
            'x1' => 70, // 左2.5cm
            'x2' => 530, // 右2.3cm
            'y2' => 710,
            
            'headerY1' => 746,
            'headerY2' => 726,
            
            'cellWidth' => 213,
            'cellWidthOther' => 34,
            'cellHeight' => 145, // 表格高度
            'cellHeightOther' => 20, // 表格高度间隙
        ];
        $aTable = [
            1 => [
                'x1' => $aPoint['x1'],
                'y1' => $aPoint['y2'] - $aPoint['cellHeight'],
                'x2' => $aPoint['x1'] + $aPoint['cellWidth'],
                'y2' => $aPoint['y2'],
            ],
            
            2 => [
                'x1' => $aPoint['x1'] + $aPoint['cellWidth'] + $aPoint['cellWidthOther'],
                'y1' => $aPoint['y2'] - $aPoint['cellHeight'],
                'x2' => $aPoint['x1'] + 2 * $aPoint['cellWidth'] + $aPoint['cellWidthOther'],
                'y2' => $aPoint['y2'],
            ]
        ];
        
        $sTake = 12;
        $sBookmark = 0;
        $sTitle = $aValue['title'];
        $sRemark = $aValue['remark'] ?? '';
        $aValue = $aValue['value'];
        $sSkip = ceil(count($aValue) / $sTake);
        for ($sPage = 1; $sPage <= $sSkip; $sPage ++)
        {
            $oCatalog->begin_page_ext(0, 0, 'width=a4.width height=a4.height');
            if (!$sBookmark && $sRemark) {
                $sBookmark = $oCatalog->create_bookmark($sTitle.' '.$sRemark, sprintf('parent=%d', 0));
            }
            
            // 页头设置
            $sOption = 'fontname={font/arial_bd} embedding fontsize=16 encoding=unicode fillcolor=%s';
            $sOption = sprintf($sOption, $this->aOption['colors']['font']);
            $oCatalog->fit_textline($sTitle, $aPoint['x1'], $aPoint['headerY1'], $sOption);
            
            $sOption = 'fontname={font/arial} embedding fontsize=14 encoding=unicode fillcolor=%s';
            $sOption = sprintf($sOption, $this->aOption['colors']['font']);
            $oCatalog->fit_textline('Photo…………………………………………………………………………………', $aPoint['x1'], $aPoint['headerY2'], $sOption);
            
            for ($sRow = 1; $sRow <= 4; $sRow ++)
            {
                for ($sCol = 1; $sCol <= 2; $sCol ++)
                {
                    if (!$aValue) {
                        continue;
                    }
                    $aShift = array_shift($aValue);
                    
                    $sResult = 0;
                    $sOption = 'colwidth=%s rowheight=%s fittextline={font=%s fontsize=14 fitmethod=auto} matchbox={fillcolor=%s}';
                    $sOption = sprintf($sOption, $aPoint['cellWidth'], 28, $this->aOption['font']['arial_bd'], $this->aOption['colors']['back']);
                    $sResult = $oCatalog->addTableCell($sResult, 1, 1, $aShift['col1'], $sOption);
                    
                    $oImage = $oCatalog->loadImage('auto', $aShift['col2'], '');
                    $sOption = sprintf('colwidth=%s rowheight=%s image=%s fitimage={position={center}} margin=10', $aPoint['cellWidth'], $aPoint['cellHeight'] - 28, $oImage);
                    $sResult = $oCatalog->addTableCell($sResult, 1, 2, '', $sOption);
                    
                    // 生成表格
                    $sOption = 'header=0 rowheightdefault=auto stroke={{line=frame linewidth=1.5 strokecolor=%s}}';
                    $sOption = sprintf($sOption, $this->aOption['colors']['line']);
                    $oCatalog->fit_table(
                        $sResult,
                        $aTable[$sCol]['x1'],
                        $aTable[$sCol]['y1'] - ($sRow - 1) * $aPoint['cellHeight'] - ($sRow - 1) * $aPoint['cellHeightOther'],
                        $aTable[$sCol]['x2'],
                        $aTable[$sCol]['y2'] - ($sRow - 1) * $aPoint['cellHeight'] - ($sRow - 1) * $aPoint['cellHeightOther'],
                        $sOption
                    );
                }
            }
            
            $oCatalog = $this->pagination($oCatalog, $this->aOption['pagination']);
            $oCatalog->end_page_ext('');
            $this->aOption['pagination'] ++;
        }
        
        return $sBuffer ? ($this->aOption['pagination'] - 1) : $oCatalog;
    }
    
    /**
     * 照片排版2
     *
     * @param PDFlib $oCatalog
     * @param array $aValue  数据
     * @param false $sBuffer 是否只返回页码
     *
     * @example
     * [
     *      'style' => 'photoGuideByWaterPump', // 版式
     *      'title' => 'Water pump', // 标题
     *      'value' => [
     *          // 图片使用绝对路径, 避免不必要的问题
     *          ['col1' => '9223001', 'col2' => [['brand' => 'SEAT', 'number' => '191407181A'], ...], 'col3' => '/home/path/name.jpg'],
     *          ['col1' => '9223001', 'col2' => [['brand' => 'SEAT', 'number' => '191407181A'], ...], 'col3' => '/home/path/name.jpg'],
     *          ...
     *      ],
     * ]
     *
     * @return int|PDFlib
     */
    public function photoGuideBySuspension(PDFlib $oCatalog, array $aValue, bool $sBuffer = false)
    {
        $sTake = 12;
        $aPoint = [
            'headerY1' => 774,
            'headerY2' => 754,
            
            'cellWidth' => ($this->aOption['point']['x2'] - $this->aOption['point']['x1']) / 4, // 表格宽度
            'cellHeight' => 218, // 表格高度
            'cellMargin' => 15, // 表格之间的间隔
        ];
        
        // 设置表格坐标
        $aTable = [];
        $sStart = 737;
        for ($sRow = 1; $sRow <= 3; $sRow ++)
        {
            for ($sCol = 1; $sCol <= 4; $sCol ++)
            {
                $aTable[] = [
                    'x1' => $this->aOption['point']['x1'] + ($sCol - 1) * $aPoint['cellWidth'], // 左下x
                    'y1' => $sStart - $aPoint['cellHeight'], // 左下y
                    'x2' => $this->aOption['point']['x1'] + $sCol * $aPoint['cellWidth'], // 右上x
                    'y2' => $sStart, // 右上y
                ];
            }
            $sStart = $sStart - $aPoint['cellHeight'] - $aPoint['cellMargin'];
        }
        
        // 内容页面
        $sBookmark = 0;
        $sTitle = $aValue['title'];
        $sRemark = $aValue['remark'] ?? '';
        $aValue = $aValue['value'];
        $sSkip = ceil(count($aValue) / $sTake);
        for ($sPage = 1; $sPage <= $sSkip; $sPage ++)
        {
            $oCatalog->begin_page_ext(0, 0, 'width=a4.width height=a4.height');
            if (!$sBookmark && $sRemark) {
                $sBookmark = $oCatalog->create_bookmark($sTitle.' '.$sRemark, sprintf('parent=%d', 0));
            }
            
            // 页头设置
            $sOption = 'fontname={font/arial_bd} embedding fontsize=16 encoding=unicode fillcolor=%s';
            $sOption = sprintf($sOption, $this->aOption['colors']['font']);
            $oCatalog->fit_textline($sTitle, $this->aOption['point']['x1'], $aPoint['headerY1'], $sOption);
            
            $sOption = 'fontname={font/arial} embedding fontsize=14 encoding=unicode fillcolor=%s';
            $sOption = sprintf($sOption, $this->aOption['colors']['font']);
            $oCatalog->fit_textline('Photo……………………………………………………………………………………………', $this->aOption['point']['x1'], $aPoint['headerY2'], $sOption);
            
            // 绘制表格
            foreach ($aTable as $aItem)
            {
                if (!$aValue) {
                    continue;
                }
                $aShift = array_shift($aValue);
                
                // 填充单元格
                $sResult = 0;
                for ($sRow = 1; $sRow <= 3; $sRow ++)
                {
                    switch ($sRow)
                    {
                        case 1:
                            // 标题列 28
                            $sValue = $aShift['col1'];
                            $sOption = 'colwidth=%s rowheight=%s fittextline={font=%s fontsize=14} matchbox={fillcolor=%s}';
                            $sOption = sprintf($sOption, $aPoint['cellWidth'], 28, $this->aOption['font']['arial_bd'], $this->aOption['colors']['back']);
                            break;
                        
                        case 2:
                            // 内容列 115
                            $sValue = '';
                            $sChild = 0;
                            for ($sRun = 1; $sRun <= 10; $sRun ++)
                            {
                                $sText = $aShift['col2'][$sRun - 1]['brand'] ?? '';
                                $sOption = 'colwidth=%s rowheight=%s fittextline={font=%s fitmethod=auto fontsize=8 position={left center}} margin=2';
                                $sOption = sprintf($sOption, 60, 11, $this->aOption['font']['arial_bd'], 8);
                                $sChild = $oCatalog->addTableCell($sChild, 1, $sRun, $sText, $sOption);
    
                                $sText = $aShift['col2'][$sRun - 1]['number'] ?? '';
                                $sOption = 'colwidth=%s rowheight=%s fittextline={font=%s fontsize=8 fitmethod=auto position={left center}} margin=2';
                                $sOption = sprintf($sOption, $aPoint['cellWidth'] - 60, 11, $this->aOption['font']['arial_bd']);
                                $sChild = $oCatalog->addTableCell($sChild, 2, $sRun, $sText, $sOption);
                                
                            }
                            $sOption = 'header=0 rowheightdefault=auto stroke={{line=other linewidth=0}}';
                            $oCatalog->fit_table($sChild, $aItem['x1'], $aItem['y1'] + 75, $aItem['x2'], $aItem['y2'] - 28, $sOption);
                            
                            $sOption = 'colwidth=%s rowheight=%s fittextline={font=%s fontsize=14 fitmethod=auto}';
                            $sOption = sprintf($sOption, $aPoint['cellWidth'], 115, $this->aOption['font']['arial']);
                            break;
                        
                        case 3:
                            // 图片列 75
                            $sValue = '';
                            $oImage = $oCatalog->loadImage('auto', $aShift['col3'], '');
                            $sOption = sprintf('colwidth=%s rowheight=%s image=%s fitimage={position={center}} margin=5', $aPoint['cellWidth'], 75, $oImage);
                            break;
                        default: $sValue = ''; $sOption = '';break;
                    }
                    
                    $sResult = $oCatalog->addTableCell($sResult, 1, $sRow, $sValue, $sOption);
                }
                
                // 生成表格
                $sOption = 'header=0 rowheightdefault=auto stroke={{line=frame linewidth=1 strokecolor=%s}}';
                $sOption = sprintf($sOption, $this->aOption['colors']['line']);
                $oCatalog->fit_table($sResult, $aItem['x1'], $aItem['y1'], $aItem['x2'], $aItem['y2'], $sOption);
            }
            
            $oCatalog = $this->pagination($oCatalog, $this->aOption['pagination']);
            $oCatalog->end_page_ext('');
            $this->aOption['pagination'] ++;
        }
        
        return $sBuffer ? ($this->aOption['pagination'] - 1) : $oCatalog;
    }
    
    /**
     * 照片排版3
     *
     * @param PDFlib $oCatalog
     * @param array $aValue  数据
     * @param false $sBuffer 是否只返回页码
     *
     * @example
     * [
     *      'style' => 'photoGuideByBearing', // 版式
     *      'title' => 'Water pump', // 标题
     *      'value' => [
     *          // 图片使用绝对路径, 避免不必要的问题
     *          ['col1' => 9710001, 'col2' => [8941012430, 94101243, 204194], 'col3' => ['D=34', 'd=24', 'H=18.5', 'W=46'], 'col4' => '/path/name.jpg']
     *          ...
     *      ],
     * ]
     *
     * @return int|PDFlib
     */
    public function photoGuideByBearing(PDFlib $oCatalog, array $aValue, bool $sBuffer = false)
    {
        $aPoint = array_merge($this->aOption['point'], [
            'headerY1' => 788,
            'headerY2' => 765,
            
            'cellWidth' => ($this->aOption['point']['x2'] - $this->aOption['point']['x1']) / 2,
            'cellWidthOther' => 90,
            
            'cellHeight' => 136,
            'cellHeightOther' => 15,
        ]);
        
        $sStyle = $aValue['style'];
        switch ($sStyle)
        {
            case 'photoGuideByTensioner':
                $aPoint['about'] = $this->aOption['image']['tensionerByBearing'];
                break;
            
            default:
                $aPoint['about'] = $this->aOption['image']['clutchByBearing'];
                break;
        }
        
        // 介绍图
        $aPoint['table1'] = [
            // 左下点
            'x1' => $this->aOption['point']['x1'],
            'y1' => $aPoint['headerY2'] - 129,
            // 右上点
            'x2' => $this->aOption['point']['x2'],
            'y2' => $aPoint['headerY2'],
        ];
        
        $sTake = 8;
        $sBookmark = 0;
        $sTitle = $aValue['title'];
        $sRemark = $aValue['remark'] ?? '';
        $aValue = $aValue['value'];
        $sSkip = ceil(count($aValue) / $sTake);
        for ($sPage = 1; $sPage <= $sSkip; $sPage ++)
        {
            $sStart = $aPoint['headerY2'] - 129;
            $oCatalog->begin_page_ext(0, 0, 'width=a4.width height=a4.height');
            if (!$sBookmark && $sRemark) {
                $sBookmark = $oCatalog->create_bookmark($sTitle.' '.$sRemark, sprintf('parent=%d', 0));
            }
            
            $sOption = 'fontname={font/arial_bd} embedding fontsize=16 encoding=unicode fillcolor=%s';
            $sOption = sprintf($sOption, $this->aOption['colors']['font']);
            $oCatalog->fit_textline($sTitle, $aPoint['x1'], $aPoint['headerY1'], $sOption);
            
            $sOption = 'fontname={font/arial} embedding fontsize=14 encoding=unicode fillcolor=%s';
            $sOption = sprintf($sOption, $this->aOption['colors']['font']);
            $oCatalog->fit_textline('Photo………………………………………………………………………………………', $aPoint['x1'], $aPoint['headerY2'], $sOption);
            
            $sResult = 0;
            $oImage = $oCatalog->loadImage('auto', $aPoint['about'], '');
            $sOption = sprintf('image=%s fitimage={position={center}} margin=5', $oImage);
            $sResult = $oCatalog->addTableCell($sResult, 1, 1, '', $sOption);
            $sOption = 'header=0 rowheightdefault=auto';
            $oCatalog->fit_table($sResult, $aPoint['table1']['x1'], $aPoint['table1']['y1'], $aPoint['table1']['x2'], $aPoint['table1']['y2'], $sOption);
            
            for ($sRow = 0; $sRow < 4; $sRow ++)
            {
                for ($sCol = 0; $sCol < 2; $sCol ++)
                {
                    $aShift = array_shift($aValue);
                    
                    $sResult = 0;
                    $sOption = 'colwidth=%s rowheight=%s fittextline={font=%s fontsize=14 fitmethod=auto position={center}} matchbox={fillcolor=%s} colspan=5';
                    $sOption = sprintf($sOption, $aPoint['cellWidth'], 28, $this->aOption['font']['arial_bd'], $this->aOption['colors']['back']);
                    $sResult = $oCatalog->addTableCell($sResult, 1, 1, $aShift['col1'], $sOption);
                    
                    $sFlow = 0;
                    $aFlow = $aShift['col2'] ?? [];
                    if ($aFlow)
                    {
                        array_unshift($aFlow, 'Re .No.');
                        $aFlow = array_slice($aFlow, 0, 10);
                    }
                    $sOption = 'fontname=font/arial_bd encoding=unicode fontsize=8';
                    $sFlow = $oCatalog->add_textflow($sFlow, implode(" \n", $aFlow), $sOption);
                    
                    $sOption = 'colwidth=%s rowheight=%s textflow=%s fittextflow={verticalalign=top} margin=3 rowspan=2';
                    $sOption = sprintf($sOption, $aPoint['cellWidthOther'], $aPoint['cellHeight'] - 28, $sFlow);
                    $sResult = $oCatalog->addTableCell($sResult, 1, 2, '', $sOption);
                    
                    for ($sRun = 2; $sRun < 6; $sRun ++)
                    {
                        $sWidth = ($aPoint['cellWidth'] - $aPoint['cellWidthOther']) / 4;
                        $sShift = $aShift['col3'] ? array_shift($aShift['col3']) : '';
                        $sOption = 'colwidth=%s rowheight=%s fittextline={font=%s fontsize=8 fitmethod=auto position={right}} margin=3';
                        $sOption = sprintf($sOption, $sWidth, 12, $this->aOption['font']['arial_bd']);
                        $sResult = $oCatalog->addTableCell($sResult, $sRun, 2, $sShift, $sOption);
                    }
                    
                    $sImage = $aShift['col4'] ?? '';
                    $sOption = sprintf('rowheight=%s colspan=4',  $aPoint['cellHeight'] - 40);
                    if (is_file($sImage))
                    {
                        $oImage = $oCatalog->loadImage('auto', $sImage, '');
                        $sOption = 'rowheight=%s image=%s fitimage={position={center}} colspan=4 margin=10';
                        $sOption = sprintf($sOption,  $aPoint['cellHeight'] - 40, $oImage);
                    }
                    $sResult = $oCatalog->addTableCell($sResult, 2, 3, '', $sOption);
                    
                    $sOption = 'header=0 rowheightdefault=auto stroke={{line=frame linewidth=1 strokecolor=%s}}';
                    $sOption = sprintf($sOption, $this->aOption['colors']['line']);
                    $oCatalog->fit_table(
                        $sResult,
                        $aPoint['x1'] + $sCol * $aPoint['cellWidth'],
                        $sStart - $aPoint['cellHeight'],
                        $aPoint['x1'] + ($sCol + 1) * $aPoint['cellWidth'],
                        $sStart,
                        $sOption
                    );
                }
                $sStart = $sStart - $aPoint['cellHeight'] - $aPoint['cellHeightOther'];
            }
            
            $oCatalog = $this->pagination($oCatalog, $this->aOption['pagination']);
            $oCatalog->end_page_ext('');
            $this->aOption['pagination'] ++;
        }
        
        return $sBuffer ? ($this->aOption['pagination'] - 1) : $oCatalog;
    }
    
    /**
     * 交叉号排版1(70)
     *
     * @param PDFlib $oCatalog
     * @param array $aValue  数据
     * @param false $sBuffer 是否只返回页码
     *
     * @example
     * [
     *      'style' => 'cross1Guide', // 版式
     *      'title' => 'Cross Reference List', // 标题
     *      'value' => [
     *          ['col' => '厂商', 'col1' => '号码1', 'col2' => '号码2'],
     *          ['col' => 'OE', 'col1' => 'VKBA1338', 'col2' => '9235001K'],
     *          ['col' => 'OE', 'col1' => 'VKBA1338', 'col2' => '9235001K'],
     *          ['col' => 'SKF', 'col1' => 'VKBA1338', 'col2' => '9235001K'],
     *          ...
     *      ],
     * ]
     *
     * @return int|PDFlib
     */
    public function cross1Guide(PDFlib $oCatalog, array $aValue, bool $sBuffer = false)
    {
        $sLine = 5;
        $aPoint = array_merge($this->aOption['point'], [
            'cellWidth' => $this->aOption['point']['x2'] - $this->aOption['point']['x1'],
            'cellHeight' => 11,
        ]);
        $aPoint['cellWidthOter'] = $aPoint['cellWidth'] / $sLine;
        $aPoint['cellWidth1'] = 64;
        $aPoint['cellWidth2'] = $aPoint['cellWidthOter'] - $aPoint['cellWidth1'];
        
        // 内容页面
        $sData = 0;
        $sBegin = true;
        $sWhile = true;
        $sResult = 0;
        $sBrand = '';
        $aTitle = [1 => 'COMPETITOR', $this->aOption['gTitle']];
        $sRemark = $aValue['remark'] ?? '';
        $aValue = $aValue['value'];
        while ($sWhile)
        {
            // 头部
            if ($sBegin)
            {
                $sBrand = '';
                $sResult = 0;
                $oCatalog->begin_page_ext(0, 0, 'width=a4.width height=a4.height');
                if (!$sData && $sRemark) {
                    $oCatalog->create_bookmark($sRemark, sprintf('parent=%d', 0)); $sData = 1;
                }
                
                for ($sCol = 1; $sCol <= $sLine; $sCol ++)
                {
                    $sChild = 0;
                    for ($sRun = 1; $sRun <= 2; $sRun ++)
                    {
                        $sOption = 'colwidth=%s rowheight=%s fittextline={font=%s fontsize=8 fitmethod=auto fillcolor=%s position={center}}';
                        $sOption = sprintf($sOption,$aPoint[sprintf('cellWidth%d', $sRun)], $aPoint['cellHeight'] * 2, $this->aOption['font']['arial_bd'], $this->aOption['colors']['font']);
                        $sChild = $oCatalog->addTableCell($sChild, $sRun, 1, $aTitle[$sRun], $sOption);
                    }
                    $sOption = 'header=0 rowheightdefault=auto stroke={{line=vert1 linewidth=1 strokecolor=%s} {line=hor1 linewidth=1 strokecolor=%s}}';
                    $sOption = sprintf($sOption, $this->aOption['colors']['line'], $this->aOption['colors']['line']);
                    $oCatalog->fit_table(
                        $sChild,
                        $aPoint['x1'] + ($sCol - 1) * $aPoint['cellWidthOter'],
                        $aPoint['y2'] - 2 * $aPoint['cellHeight'],
                        $aPoint['x1'] + $sCol * $aPoint['cellWidthOter'],
                        $aPoint['y2'],
                        $sOption
                    );
                    
                    $sOption = 'colwidth=%s rowheight=%s fittextline={font=%s fontsize=8 fitmethod=auto position={center}}';
                    $sOption = sprintf($sOption,$aPoint['cellWidthOter'], $aPoint['cellHeight'] * 2, $this->aOption['font']['arial_bd']);
                    $sResult = $oCatalog->addTableCell($sResult, $sCol, 1, '', $sOption);
                }
                $sBegin = false;
            }
            
            // 页面内容
            $aShift = [];
            for ($sCol = 1; $sCol <= $sLine; $sCol ++)
            {
                for ($sRun = 1; $sRun <= 68; $sRun++)
                {
                    if (!$aShift) {
                        $aShift = $aValue ? array_shift($aValue) : ['col' => $sBrand, 'col1' => '', 'col2' => ''];
                    }
                    
                    // 厂商
                    if ($sBrand != $aShift['col'])
                    {
                        if ($sRun > 67) {
                            continue;
                        }
                        
                        $sChild = 0;
                        $sOption = 'colwidth=%s rowheight=%s fittextline={font=%s fontsize=12 fitmethod=auto fillcolor=%s position={center}}';
                        $sOption = sprintf($sOption,$aPoint['cellWidthOter'], $aPoint['cellHeight'] * 2, $this->aOption['font']['arial_bd'], $this->aOption['colors']['font']);
                        $sChild = $oCatalog->addTableCell($sChild, 1, 1, $aShift['col'], $sOption);
                        
                        $sOption = 'header=0 rowheightdefault=auto stroke={{line=horfirst linewidth=1 strokecolor=%s} {line=hor1 linewidth=1 strokecolor=%s}}';
                        $sOption = sprintf($sOption, $this->aOption['colors']['line'], $this->aOption['colors']['line']);
                        $oCatalog->fit_table(
                            $sChild,
                            $aPoint['x1'] + ($sCol - 1) * $aPoint['cellWidthOter'],
                            $aPoint['y2'] - (2 + $sRun + 1) * $aPoint['cellHeight'],
                            $aPoint['x1'] + $sCol * $aPoint['cellWidthOter'],
                            $aPoint['y2'] - (2 + $sRun - 1) * $aPoint['cellHeight'],
                            $sOption
                        );
                        
                        $sBrand = $aShift['col'];
                        $sRun = $sRun + 2;
                    }
                    
                    if ($sRun > 68) {
                        continue;
                    }
                    
                    // 号码
                    $sChild = 0;
                    $sOption = 'colwidth=%s rowheight=%s fittextline={font=%s fontsize=7 fitmethod=auto position={center}}';
                    $sOption = sprintf($sOption,$aPoint['cellWidth1'], $aPoint['cellHeight'], $this->aOption['font']['arial']);
                    $sChild = $oCatalog->addTableCell($sChild, 1, 1, $aShift['col1'], $sOption);
                    
                    $sOption = 'colwidth=%s rowheight=%s fittextline={font=%s fitmethod=auto fontsize=7 position={center}}';
                    $sOption = sprintf($sOption,$aPoint['cellWidth2'], $aPoint['cellHeight'], $this->aOption['font']['arial_bd']);
                    $sChild = $oCatalog->addTableCell($sChild, 2, 1, $aShift['col2'], $sOption);
                    
                    $sOption = 'header=0 rowheightdefault=auto stroke={{line=vert1 linewidth=0.5 strokecolor=%s}}';
                    $sOption = sprintf($sOption, $this->aOption['colors']['line']);
                    $oCatalog->fit_table(
                        $sChild,
                        $aPoint['x1'] + ($sCol - 1) * $aPoint['cellWidthOter'],
                        $aPoint['y2'] - (2 + $sRun + 1) * $aPoint['cellHeight'],
                        $aPoint['x1'] + $sCol * $aPoint['cellWidthOter'],
                        $aPoint['y2'] - (2 + $sRun - 1) * $aPoint['cellHeight'],
                        $sOption
                    );
                    $aShift = [];
                }
                
                $sOption = 'colwidth=%s rowheight=%s fittextline={font=%s fontsize=8 fitmethod=auto position={center}}';
                $sOption = sprintf($sOption,$aPoint['cellWidthOter'], $aPoint['cellHeight'] * 75, $this->aOption['font']['arial_bd']);
                $sResult = $oCatalog->addTableCell($sResult, $sCol, 1, '', $sOption);
            }
            
            if (!$aValue) {
                $sWhile = false;
            }
            
            // 结尾
            if ($sWhile || ($sCol > $sLine))
            {
                $sBegin = true;
                $sOption = 'header=0 rowheightdefault=auto stroke={{line=other linewidth=1 strokecolor=%s} }';
                $sOption = sprintf($sOption, $this->aOption['colors']['line']);
                $oCatalog->fit_table($sResult, $aPoint['x1'], $aPoint['y1'], $aPoint['x2'], $aPoint['y2'], $sOption);
                
                $oCatalog = $this->pagination($oCatalog, $this->aOption['pagination']);
                $oCatalog->end_page_ext('');
                $this->aOption['pagination'] ++;
            }
        }
        
        return $sBuffer ? ($this->aOption['pagination'] - 1) : $oCatalog;
    }
    
    /**
     * 交叉号排版2
     *
     * @param PDFlib $oCatalog
     * @param array $aValue  数据
     * @param false $sBuffer 是否只返回页码
     *
     * @example
     * [
     *      'style' => 'cross2Guide', // 版式
     *      'title' => 'Cross Reference List', // 标题
     *      'value' => [
     *          ['col' => '厂商', 'col1' => '号码1', 'col2' => '号码2'],
     *          ['col' => 'OE', 'col1' => 'VKBA1338', 'col2' => '9235001K'],
     *          ['col' => 'OE', 'col1' => 'VKBA1338', 'col2' => '9235001K'],
     *          ['col' => 'SKF', 'col1' => 'VKBA1338', 'col2' => '9235001K'],
     *          ...
     *      ],
     * ]
     *
     * @return int|PDFlib
     */
    public function cross2Guide(PDFlib $oCatalog, array $aValue, bool $sBuffer = false)
    {
        $sLine = 4;
        $aPoint = array_merge($this->aOption['point'], [
            'cellWidth' => $this->aOption['point']['x2'] - $this->aOption['point']['x1'],
            'cellHeight' => 11,
        ]);
        $aPoint['cellWidthOter'] = $aPoint['cellWidth'] / $sLine;
        $aPoint['cellWidth1'] = 64;
        $aPoint['cellWidth2'] = $aPoint['cellWidthOter'] - $aPoint['cellWidth1'];
        
        // 内容页面
        $sData = 0;
        $sBegin = true;
        $sWhile = true;
        $sResult = 0;
        $sBrand = '';
        $aTitle = [1 => 'COMPETITOR', $this->aOption['gTitle']];
        $sRemark = $aValue['remark'] ?? '';
        $aValue = $aValue['value'];
        while ($sWhile)
        {
            // 头部
            if ($sBegin)
            {
                $sBrand = '';
                $sResult = 0;
                $oCatalog->begin_page_ext(0, 0, 'width=a4.width height=a4.height');
                if (!$sData && $sRemark) {
                    $oCatalog->create_bookmark($sRemark, sprintf('parent=%d', 0)); $sData = 1;
                }
                
                for ($sCol = 1; $sCol <= $sLine; $sCol ++)
                {
                    $sChild = 0;
                    for ($sRun = 1; $sRun <= 2; $sRun ++)
                    {
                        $sOption = 'colwidth=%s rowheight=%s fittextline={font=%s fontsize=8 fitmethod=auto fillcolor=%s position={center}}';
                        $sOption = sprintf($sOption,$aPoint[sprintf('cellWidth%d', $sRun)], $aPoint['cellHeight'] * 2, $this->aOption['font']['arial_bd'], $this->aOption['colors']['font']);
                        $sChild = $oCatalog->addTableCell($sChild, $sRun, 1, $aTitle[$sRun], $sOption);
                    }
                    $sOption = 'header=0 rowheightdefault=auto stroke={{line=vert1 linewidth=1 strokecolor=%s} {line=hor1 linewidth=1 strokecolor=%s}}';
                    $sOption = sprintf($sOption, $this->aOption['colors']['line'], $this->aOption['colors']['line']);
                    $oCatalog->fit_table(
                        $sChild,
                        $aPoint['x1'] + ($sCol - 1) * $aPoint['cellWidthOter'],
                        $aPoint['y2'] - 2 * $aPoint['cellHeight'],
                        $aPoint['x1'] + $sCol * $aPoint['cellWidthOter'],
                        $aPoint['y2'],
                        $sOption
                    );
                    
                    $sOption = 'colwidth=%s rowheight=%s fittextline={font=%s fontsize=8 fitmethod=auto position={center}}';
                    $sOption = sprintf($sOption,$aPoint['cellWidthOter'], $aPoint['cellHeight'] * 2, $this->aOption['font']['arial_bd']);
                    $sResult = $oCatalog->addTableCell($sResult, $sCol, 1, '', $sOption);
                }
                $sBegin = false;
            }
            
            // 页面内容
            $aShift = [];
            for ($sCol = 1; $sCol <= $sLine; $sCol ++)
            {
                for ($sRun = 1; $sRun <= 68; $sRun++)
                {
                    if (!$aShift) {
                        $aShift = $aValue ? array_shift($aValue) : ['col' => $sBrand, 'col1' => '', 'col2' => ''];
                    }
                    
                    // 厂商
                    if ($sBrand != $aShift['col'])
                    {
                        if ($sRun > 67) {
                            continue;
                        }
                        
                        $sChild = 0;
                        $sOption = 'colwidth=%s rowheight=%s fittextline={font=%s fontsize=12 fitmethod=auto fillcolor=%s position={center}}';
                        $sOption = sprintf($sOption,$aPoint['cellWidthOter'], $aPoint['cellHeight'] * 2, $this->aOption['font']['arial_bd'], $this->aOption['colors']['font']);
                        $sChild = $oCatalog->addTableCell($sChild, 1, 1, $aShift['col'], $sOption);
                        
                        $sOption = 'header=0 rowheightdefault=auto stroke={{line=horfirst linewidth=1 strokecolor=%s} {line=hor1 linewidth=1 strokecolor=%s}}';
                        $sOption = sprintf($sOption, $this->aOption['colors']['line'], $this->aOption['colors']['line']);
                        $oCatalog->fit_table(
                            $sChild,
                            $aPoint['x1'] + ($sCol - 1) * $aPoint['cellWidthOter'],
                            $aPoint['y2'] - (2 + $sRun + 1) * $aPoint['cellHeight'],
                            $aPoint['x1'] + $sCol * $aPoint['cellWidthOter'],
                            $aPoint['y2'] - (2 + $sRun - 1) * $aPoint['cellHeight'],
                            $sOption
                        );
                        
                        $sBrand = $aShift['col'];
                        $sRun = $sRun + 2;
                    }
                    
                    if ($sRun > 68) {
                        continue;
                    }
                    
                    // 号码
                    $sChild = 0;
                    $sOption = 'colwidth=%s rowheight=%s fittextline={font=%s fontsize=8 fitmethod=auto position={center}}';
                    $sOption = sprintf($sOption,$aPoint['cellWidth1'], $aPoint['cellHeight'], $this->aOption['font']['arial']);
                    $sChild = $oCatalog->addTableCell($sChild, 1, 1, $aShift['col1'], $sOption);
                    
                    $sOption = 'colwidth=%s rowheight=%s fittextline={font=%s fontsize=8 fitmethod=auto position={center}}';
                    $sOption = sprintf($sOption,$aPoint['cellWidth2'], $aPoint['cellHeight'], $this->aOption['font']['arial_bd']);
                    $sChild = $oCatalog->addTableCell($sChild, 2, 1, $aShift['col2'], $sOption);
                    
                    $sOption = 'header=0 rowheightdefault=auto stroke={{line=vert1 linewidth=0.5 strokecolor=%s}}';
                    $sOption = sprintf($sOption, $this->aOption['colors']['line']);
                    $oCatalog->fit_table(
                        $sChild,
                        $aPoint['x1'] + ($sCol - 1) * $aPoint['cellWidthOter'],
                        $aPoint['y2'] - (2 + $sRun + 1) * $aPoint['cellHeight'],
                        $aPoint['x1'] + $sCol * $aPoint['cellWidthOter'],
                        $aPoint['y2'] - (2 + $sRun - 1) * $aPoint['cellHeight'],
                        $sOption
                    );
                    $aShift = [];
                }
                
                $sOption = 'colwidth=%s rowheight=%s fittextline={font=%s fontsize=8 fitmethod=auto position={center}}';
                $sOption = sprintf($sOption,$aPoint['cellWidthOter'], $aPoint['cellHeight'] * 75, $this->aOption['font']['arial_bd']);
                $sResult = $oCatalog->addTableCell($sResult, $sCol, 1, '', $sOption);
            }
            
            if (!$aValue) {
                $sWhile = false;
            }
            
            // 结尾
            if ($sWhile || ($sCol > $sLine))
            {
                $sBegin = true;
                $sOption = 'header=0 rowheightdefault=auto stroke={{line=other linewidth=1 strokecolor=%s} }';
                $sOption = sprintf($sOption, $this->aOption['colors']['line']);
                $oCatalog->fit_table($sResult, $aPoint['x1'], $aPoint['y1'], $aPoint['x2'], $aPoint['y2'], $sOption);
                
                $oCatalog = $this->pagination($oCatalog, $this->aOption['pagination']);
                $oCatalog->end_page_ext('');
                $this->aOption['pagination'] ++;
            }
        }
        
        return $sBuffer ? ($this->aOption['pagination'] - 1) : $oCatalog;
    }
    
    /**
     * 交叉号排版3
     *
     * @param PDFlib $oCatalog
     * @param array $aValue  数据
     * @param false $sBuffer 是否只返回页码
     *
     * @example
     * [
     *      'style' => 'cross2Guide', // 版式
     *      'title' => 'Cross Reference List', // 标题
     *      'value' => [
     *          ['col' => '厂商', 'col1' => '号码1', 'col2' => '号码2'],
     *          ['col' => 'OE', 'col1' => 'VKBA1338', 'col2' => '9235001K'],
     *          ['col' => 'OE', 'col1' => 'VKBA1338', 'col2' => '9235001K'],
     *          ['col' => 'SKF', 'col1' => 'VKBA1338', 'col2' => '9235001K'],
     *          ...
     *      ],
     * ]
     *
     * @return int|PDFlib
     */
    public function cross3Guide(PDFlib $oCatalog, array $aValue, bool $sBuffer = false)
    {
        $sLine = 4;
        $aPoint = array_merge($this->aOption['point'], [
            'y2' => 781,
            'cellWidth' => $this->aOption['point']['x2'] - $this->aOption['point']['x1'],
            'cellHeight' => 11,
        ]);
        $aPoint['cellWidthOter'] = $aPoint['cellWidth'] / $sLine;
        $aPoint['cellWidth1'] = 64;
        $aPoint['cellWidth2'] = $aPoint['cellWidthOter'] - $aPoint['cellWidth1'];
        
        // 内容页面
        $sData = 0;
        $sBegin = true;
        $sWhile = true;
        $sResult = 0;
        $sBrand = '';
        $aTitle = [1 => $this->aOption['gTitle'], 'KYB Ref'];
        $sRemark = $aValue['remark'] ?? '';
        $aValue = $aValue['value'];
        while ($sWhile)
        {
            // 头部
            if ($sBegin)
            {
                $sBrand = '';
                $sResult = 0;
                $oCatalog->begin_page_ext(0, 0, 'width=a4.width height=a4.height');
                if (!$sData && $sRemark) {
                    $oCatalog->create_bookmark($sRemark, sprintf('parent=%d', 0)); $sData = 1;
                }
                
                for ($sCol = 1; $sCol <= $sLine; $sCol ++)
                {
                    $sChild = 0;
                    for ($sRun = 1; $sRun <= 2; $sRun ++)
                    {
                        $sOption = 'colwidth=%s rowheight=%s fittextline={font=%s fontsize=8 fitmethod=auto fillcolor=%s position={center}}';
                        $sOption = sprintf($sOption,$aPoint[sprintf('cellWidth%d', $sRun)], $aPoint['cellHeight'] * 2, $this->aOption['font']['arial_bd'], $this->aOption['colors']['font']);
                        $sChild = $oCatalog->addTableCell($sChild, $sRun, 1, $aTitle[$sRun], $sOption);
                    }
                    $sOption = 'header=0 rowheightdefault=auto stroke={{line=vert1 linewidth=1 strokecolor=%s} {line=hor1 linewidth=1 strokecolor=%s}}';
                    $sOption = sprintf($sOption, $this->aOption['colors']['line'], $this->aOption['colors']['line']);
                    $oCatalog->fit_table(
                        $sChild,
                        $aPoint['x1'] + ($sCol - 1) * $aPoint['cellWidthOter'],
                        $aPoint['y2'] - 2 * $aPoint['cellHeight'],
                        $aPoint['x1'] + $sCol * $aPoint['cellWidthOter'],
                        $aPoint['y2'],
                        $sOption
                    );
                    
                    $sOption = 'colwidth=%s rowheight=%s fittextline={font=%s fontsize=8 fitmethod=auto position={center}}';
                    $sOption = sprintf($sOption,$aPoint['cellWidthOter'], $aPoint['cellHeight'] * 2, $this->aOption['font']['arial_bd']);
                    $sResult = $oCatalog->addTableCell($sResult, $sCol, 1, '', $sOption);
                }
                $sBegin = false;
            }
            
            // 页面内容
            $aShift = [];
            for ($sCol = 1; $sCol <= $sLine; $sCol ++)
            {
                for ($sRun = 1; $sRun <= 64; $sRun++)
                {
                    if (!$aShift) {
                        $aShift = $aValue ? array_shift($aValue) : ['col' => $sBrand, 'col1' => '', 'col2' => ''];
                    }
                    
                    // 号码
                    $sChild = 0;
                    $sOption = 'colwidth=%s rowheight=%s fittextline={font=%s fontsize=8 fitmethod=auto position={center}}';
                    $sOption = sprintf($sOption,$aPoint['cellWidth1'], $aPoint['cellHeight'], $this->aOption['font']['arial_bd']);
                    $sChild = $oCatalog->addTableCell($sChild, 1, 1, $aShift['col1'], $sOption);
                    
                    $sOption = 'colwidth=%s rowheight=%s fittextline={font=%s fontsize=8 fitmethod=auto position={center}}';
                    $sOption = sprintf($sOption,$aPoint['cellWidth2'], $aPoint['cellHeight'], $this->aOption['font']['arial']);
                    $sChild = $oCatalog->addTableCell($sChild, 2, 1, $aShift['col2'], $sOption);
                    
                    $sOption = 'header=0 rowheightdefault=auto stroke={{line=vert1 linewidth=0 strokecolor=%s}}';
                    $sOption = sprintf($sOption, $this->aOption['colors']['line']);
                    $oCatalog->fit_table(
                        $sChild,
                        $aPoint['x1'] + ($sCol - 1) * $aPoint['cellWidthOter'],
                        $aPoint['y2'] - (2 + $sRun + 1) * $aPoint['cellHeight'],
                        $aPoint['x1'] + $sCol * $aPoint['cellWidthOter'],
                        $aPoint['y2'] - (2 + $sRun - 1) * $aPoint['cellHeight'],
                        $sOption
                    );
                    $aShift = [];
                }
                
                $sOption = 'colwidth=%s rowheight=%s fittextline={font=%s fontsize=8 fitmethod=auto position={center}}';
                $sOption = sprintf($sOption,$aPoint['cellWidthOter'], $aPoint['cellHeight'] * 66, $this->aOption['font']['arial_bd']);
                $sResult = $oCatalog->addTableCell($sResult, $sCol, 1, '', $sOption);
            }
            
            if (!$aValue) {
                $sWhile = false;
            }
            
            // 结尾
            if ($sWhile || ($sCol > $sLine))
            {
                $sBegin = true;
                $sOption = 'header=0 rowheightdefault=auto stroke={{line=other linewidth=1 strokecolor=%s} }';
                $sOption = sprintf($sOption, $this->aOption['colors']['line']);
                $oCatalog->fit_table($sResult, $aPoint['x1'], $aPoint['y1'], $aPoint['x2'], $aPoint['y2'], $sOption);
                
                $oCatalog = $this->pagination($oCatalog, $this->aOption['pagination']);
                $oCatalog->end_page_ext('');
                $this->aOption['pagination'] ++;
            }
        }
        
        return $sBuffer ? ($this->aOption['pagination'] - 1) : $oCatalog;
    }
    
    /**
     * 新号码排版1
     *
     * @param PDFlib $oCatalog
     * @param array $aValue 数据
     * @param false $sBuffer 是否只返回页码
     *
     * @example
     * [
     *      'style' => 'new1Guide', // 版式
     *      'title' => 'New applications (compared with catalogue 2020)', // 标题
     *      'value' => [
     *          '9225006F', '9228080', '9230002F', ...
     *      ],
     * ]
     *
     * @return int|PDFlib
     */
    public function new1Guide(PDFlib $oCatalog, array $aValue, bool $sBuffer = false)
    {
        $aPoint = array_merge($this->aOption['point'], [
            'cellWidth' => $this->aOption['point']['x2'] - $this->aOption['point']['x1'],
            'cellHeight' => 11,
        ]);
        $aPoint['cellWidthOter'] = $aPoint['cellWidth'] / 7;

        // 内容页面
        $sData = 0;
        $sTake = 63 * 7;
        $sRemark = $aValue['remark'] ?? '';
        $sTitle = $aValue['title'];
        $aValue = $aValue['value'];
        $sSkip = ceil(count($aValue) / $sTake);
        for ($sPage = 1; $sPage <= $sSkip; $sPage ++)
        {
            $oCatalog->begin_page_ext(0, 0, 'width=a4.width height=a4.height');
            if (!$sData && $sRemark) {
                $oCatalog->create_bookmark($sRemark, sprintf('parent=%d', 0)); $sData = 1;
            }
            
            $sResult = 0;
            $sOption = 'rowheight=%s colwidth=%s fittextline={font=%s fontsize=16 fillcolor=%s fitmethod=auto position={center}} colspan=7';
            $sOption = sprintf($sOption, $aPoint['cellHeight'] * 5, $aPoint['cellWidth'], $this->aOption['font']['arial_bd'], $this->aOption['colors']['title']);
            $sResult = $oCatalog->addTableCell($sResult, 1, 1, $sTitle, $sOption);
            
            // 2
            for ($sCol = 1; $sCol <= 7; $sCol ++)
            {
                $sOption = 'colwidth=%s rowheight=%s fittextline={font=%s fontsize=9 fillcolor=%s fitmethod=auto position={center}}';
                $sOption = sprintf($sOption, $aPoint['cellWidthOter'], $aPoint['cellHeight'] * 2, $this->aOption['font']['arial_bd'], $this->aOption['colors']['title']);
                $sResult = $oCatalog->addTableCell($sResult, $sCol, 2, $this->aOption['gTitle'], $sOption);
            }
            
            // 3
            for ($sCol = 1; $sCol <= 7; $sCol ++)
            {
                $sCell = 0;
                for ($sRow = 1; $sRow <= 63; $sRow ++)
                {
                    if (!$aValue) {
                        continue;
                    }
                    
                    $sShift = array_shift($aValue);
                    $sOption = 'colwidth=%s rowheight=%s fittextline={font=%s fontsize=7 fitmethod=auto position={center}}';
                    $sOption = sprintf($sOption, $aPoint['cellWidthOter'], $aPoint['cellHeight'], $this->aOption['font']['arial_bd']);
                    $sCell = $oCatalog->addTableCell($sCell, 1, $sRow, $sShift, $sOption);
                }
                
                if ($sCell)
                {
                    $sOption = 'header=0 rowheightdefault=auto stroke={{line=frame linewidth=0}}';
                    $oCatalog->fit_table(
                        $sCell,
                        $aPoint['x1'] + ($sCol - 1) * $aPoint['cellWidthOter'],
                        $aPoint['y1'] - 4 * $aPoint['cellHeight'],
                        $aPoint['x1'] + $sCol * $aPoint['cellWidthOter'],
                        $aPoint['y2'] - $aPoint['cellHeight'] * 7,
                        $sOption
                    );
                }
                
                $sOption = 'colwidth=%s rowheight=%s fittextline={font=%s fontsize=9 fitmethod=auto position={center}}';
                $sOption = sprintf($sOption, $aPoint['cellWidthOter'], $aPoint['cellHeight'] * 63, $this->aOption['font']['arial']);
                $sResult = $oCatalog->addTableCell($sResult, $sCol, 3, '', $sOption);
            }
            
            $sOption = 'header=0 rowheightdefault=auto stroke={{line=other linewidth=1 strokecolor=%s}}';
            $sOption = sprintf($sOption, $this->aOption['colors']['line']);
            $oCatalog->fit_table($sResult, $aPoint['x1'], $aPoint['y1'], $aPoint['x2'], $aPoint['y2'], $sOption);
            
            $oCatalog = $this->pagination($oCatalog, $this->aOption['pagination']);
            $oCatalog->end_page_ext('');
            $this->aOption['pagination'] ++;
        }
        
        return $sBuffer ? ($this->aOption['pagination'] - 1) : $oCatalog;
    }
    
    /**
     * 生成页码(居中)
     *
     * @param PDFlib $oCatalog
     * @param string $sPage 页码
     * @return PDFlib
     */
    public function pagination(PDFlib $oCatalog, string $sPage = '1'): PDFlib
    {
        $sOption = 'fontname={font/arial} embedding fontsize=12 encoding=unicode position=center';
        $oCatalog->fit_textline($sPage, 595 / 2, 24, $sOption);
        
        return $oCatalog;
    }
    
    /**
     * 输出
     *
     * @param PDFlib $oCatalog
     * @param false $sBrowser 为真时浏览器调试模式, 默认生成PDF到指定文件夹并返回文件名
     * @return mixed
     */
    public function browser(PDFlib $oCatalog, bool $sBrowser = false)
    {
        $sFile = $this->aOption['name'];
        $sBuffer = $oCatalog->get_buffer();
        if ($sBrowser)
        {
            header('Content-type: application/pdf');
            header(sprintf('Content-Length: %d', strlen($sBuffer)));
            header(sprintf('Content-Disposition: inline; filename=%s', $sFile));
            print $sBuffer;
        } else
        {
            if (!is_dir($this->aOption['path'])) {
                mkdir($this->aOption['path'], 0777, true);
            }
            
            $sPath = sprintf('%s/%s', $this->aOption['path'], $sFile);
            file_put_contents($sPath, $sBuffer);
        }
        return $sFile;
    }
    
    /**
     * 阿拉伯数字转罗马数字
     *
     * @param $sInt
     * @return array|false|string|string[]
     */
    function decToRoman($sInt)
    {
        // Return false if either $sInt is not a real number,
        // $sInt is bigger than 3999 or $sInt is lower or equal to 0:
        if(!is_numeric($sInt) || $sInt > 3999 || $sInt <= 0) {
            return false;
        }
        
        // Define the roman figures:
        $aRoman = [
            'M' => 1000,
            'D' => 500,
            'C' => 100,
            'L' => 50,
            'X' => 10,
            'V' => 5,
            'I' => 1
        ];
        
        // Calculate the needed roman figures:
        $aMount = [];
        foreach($aRoman as $sKey => $sVal)
        {
            if (($aMount[$sKey] = floor($sInt / $sVal)) > 0) {
                $sInt -= $aMount[$sKey] * $sVal;
            }
        }
            
        // Build the string:
        $aValue = [];
        $sBuild = '';
        foreach($aMount as $sKey => $sVal)
        {
            $aValue[] = ($sVal <= 3) ? str_repeat($sKey, $sVal) : $sKey . $sBuild;
            $sBuild = $sKey;
        }
        
        // Replace some spacial cases and return the string:
        return str_replace(['VIV','LXL','DCD'], ['IX','XC','CM'], implode('', $aValue));
    }
}
