      1: <?php
      2:
      3: AlphaAutoLoader::loadLib('tcpdf.php');
      4:
      5: /**
      6:  * Custom version of the TCPDF library class, allowing for any required overrides.
      7:  *
      8:  * @package alpha::util
      9:  * @since 1.0
     10:  * @author John Collins <dev@alphaframework.org>
     11:  * @version $Id: AlphaTCPDF.inc 1693 2013-12-09 23:33:24Z alphadevx $
     12:  * @license http://www.opensource.org/licenses/bsd-license.php The BSD License
     13:  * @copyright Copyright (c) 2013, John Collins (founder of Alpha Framework).
     14:  * All rights reserved.
     15:  *
     16:  * <pre>
     17:  * Redistribution and use in source and binary forms, with or
     18:  * without modification, are permitted provided that the
     19:  * following conditions are met:
     20:  *
     21:  * * Redistributions of source code must retain the above
     22:  *   copyright notice, this list of conditions and the
     23:  *   following disclaimer.
     24:  * * Redistributions in binary form must reproduce the above
     25:  *   copyright notice, this list of conditions and the
     26:  *   following disclaimer in the documentation and/or other
     27:  *   materials provided with the distribution.
     28:  * * Neither the name of the Alpha Framework nor the names
     29:  *   of its contributors may be used to endorse or promote
     30:  *   products derived from this software without specific
     31:  *   prior written permission.
     32:  *
     33:  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
     34:  * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
     35:  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
     36:  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
     37:  * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
     38:  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     39:  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
     40:  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
     41:  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     42:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     43:  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
     44:  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
     45:  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     46:  * </pre>
     47:  *
     48:  */
     49: class AlphaTCPDF extends TCPDF {
     50:     /**
     51:      * Trace logger
     52:      *
     53:      * @var Logger
     54:      * @since 1.0
     55:      */
     56:     private static $logger = null;
     57:
     58:     /**
     59:      * Overrides the TCPDF::Image method to decrypt encrypted $file paths from the Image widget, then pass
     60:      * them to the normal TCPDF::Image along with all of the other (unmodified) parameters.
     61:      *
     62:      * @param string $file Name of the file containing the image.
     63:      * @param float $x Abscissa of the upper-left corner.
     64:      * @param float $y Ordinate of the upper-left corner.
     65:      * @param float $w Width of the image in the page. If not specified or equal to zero, it is automatically calculated.
     66:      * @param float $h Height of the image in the page. If not specified or equal to zero, it is automatically calculated.
     67:      * @param string $type Image format. Possible values are (case insensitive): JPEG and PNG (whitout GD library) and all images supported by GD: GD, GD2, GD2PART, GIF, JPEG, PNG, BMP, XBM, XPM;. If not specified, the type is inferred from the file extension.
     68:      * @param mixed $link URL or identifier returned by AddLink().
     69:      * @param string $align Indicates the alignment of the pointer next to image insertion relative to image height. The value can be:<ul><li>T: top-right for LTR or top-left for RTL</li><li>M: middle-right for LTR or middle-left for RTL</li><li>B: bottom-right for LTR or bottom-left for RTL</li><li>N: next line</li></ul>
     70:      * @param boolean $resize If true resize (reduce) the image to fit $w and $h (requires GD library).
     71:      * @param int $dpi dot-per-inch resolution used on resize
     72:      * @param string $palign Allows to center or align the image on the current line. Possible values are:<ul><li>L : left align</li><li>C : center</li><li>R : right align</li><li>'' : empty string : left for LTR or right for RTL</li></ul>
     73:      * @param boolean $ismask true if this image is a mask, false otherwise
     74:      * @param mixed $imgmask image object returned by this function or false
     75:      * @param mixed $border Indicates if borders must be drawn around the image. The value can be either a number:<ul><li>0: no border (default)</li><li>1: frame</li></ul>or a string containing some or all of the following characters (in any order):<ul><li>L: left</li><li>T: top</li><li>R: right</li><li>B: bottom</li></ul>
     76:      * @since 1.0
     77:      */
     78:     public function Image($file, $x='', $y='', $w=0, $h=0, $type='', $link='', $align='', $resize=false, $dpi=300, $palign='', $ismask=false, $imgmask=false, $border=0) {
     79:         if(self::$logger == null)
     80:             self::$logger = new Logger('AlphaTCPDF');
     81:
     82:         global $config;
     83:
     84:         self::$logger->debug('Processing image file URL ['.$file.']');
     85:
     86:         try {
     87:             if(mb_strpos($file, '/tk/') !== false) {
     88:                 $start = mb_strpos($file, '/tk/')+3;
     89:                 $end = mb_strlen($file);
     90:                 $tk = mb_substr($file, $start+1, $end-($start+1));
     91:                 $decoded = FrontController::getDecodeQueryParams($tk);
     92:
     93:                 parent::Image($decoded['s'], $x, $y, $w, $h, $type, $link, $align, $resize, $dpi, $palign, $ismask, $imgmask, $border);
     94:             }else {
     95:                 // it has no query string, so threat as a regular image URL
     96:                 if(AlphaValidator::isURL($file))
     97:                     parent::Image($config->get('app.root').'/'.Image::convertImageURLToPath($file), $x, $y, $w, $h, $type, $link, $align, $resize, $dpi, $palign, $ismask, $imgmask, $border);
     98:                 else
     99:                     parent::Image($file, $x, $y, $w, $h, $type, $link, $align, $resize, $dpi, $palign, $ismask, $imgmask, $border);
    100:             }
    101:         }catch(Exception $e) {
    102:             self::$logger->error('Error processing image file URL ['.$file.'], error ['.$e->getMessage().']');
    103:             throw $e;
    104:         }
    105:     }
    106:
    107:     /**
    108:      * Process opening tags.  Overridden here to fix a bug when the image type can't be determined from the URL.
    109:      *
    110:      * @param array $dom html dom array
    111:      * @param int $key current element id
    112:      * @param boolean $cell if true add the default cMargin space to each new line (default false).
    113:      * @access protected
    114:      */
    115:     protected function openHTMLTagHandler(&$dom, $key, $cell=false) {
    116:         $tag = $dom[$key];
    117:         $parent = $dom[($dom[$key]['parent'])];
    118:         $firstorlast = ($key == 1);
    119:         // check for text direction attribute
    120:         if (isset($tag['attribute']['dir'])) {
    121:             $this->tmprtl = $tag['attribute']['dir'] == 'rtl' ? 'R' : 'L';
    122:         } else {
    123:             $this->tmprtl = false;
    124:         }
    125:         //Opening tag
    126:         switch($tag['value']) {
    127:             case 'table': {
    128:                 $cp = 0;
    129:                 $cs = 0;
    130:                 $dom[$key]['rowspans'] = array();
    131:                 if (!$this->empty_string($dom[$key]['thead'])) {
    132:                     // set table header
    133:                     $this->thead = $dom[$key]['thead'];
    134:                 }
    135:                 if (isset($tag['attribute']['cellpadding'])) {
    136:                     $cp = $this->getHTMLUnitToUnits($tag['attribute']['cellpadding'], 1, 'px');
    137:                     $this->oldcMargin = $this->cMargin;
    138:                     $this->cMargin = $cp;
    139:                 }
    140:                 if (isset($tag['attribute']['cellspacing'])) {
    141:                     $cs = $this->getHTMLUnitToUnits($tag['attribute']['cellspacing'], 1, 'px');
    142:                 }
    143:                 $this->checkPageBreak((2 * $cp) + (2 * $cs) + $this->lasth);
    144:                 break;
    145:             }
    146:             case 'tr': {
    147:                 // array of columns positions
    148:                 $dom[$key]['cellpos'] = array();
    149:                 break;
    150:             }
    151:             case 'hr': {
    152:                 $this->addHTMLVertSpace(1, $cell, '', $firstorlast, $tag['value'], false);
    153:                 $this->htmlvspace = 0;
    154:                 $wtmp = $this->w - $this->lMargin - $this->rMargin;
    155:                 if ((isset($tag['attribute']['width'])) AND ($tag['attribute']['width'] != '')) {
    156:                     $hrWidth = $this->getHTMLUnitToUnits($tag['attribute']['width'], $wtmp, 'px');
    157:                 } else {
    158:                     $hrWidth = $wtmp;
    159:                 }
    160:                 $x = $this->GetX();
    161:                 $y = $this->GetY();
    162:                 $prevlinewidth = $this->GetLineWidth();
    163:                 $this->Line($x, $y, $x + $hrWidth, $y);
    164:                 $this->SetLineWidth($prevlinewidth);
    165:                 $this->addHTMLVertSpace(1, $cell, '', !isset($dom[($key + 1)]), $tag['value'], false);
    166:                 break;
    167:             }
    168:             case 'a': {
    169:                 if (array_key_exists('href', $tag['attribute'])) {
    170:                     $this->HREF['url'] = $tag['attribute']['href'];
    171:                 }
    172:                 $this->HREF['color'] = $this->htmlLinkColorArray;
    173:                 $this->HREF['style'] = $this->htmlLinkFontStyle;
    174:                 if (array_key_exists('style', $tag['attribute'])) {
    175:                     // get style attributes
    176:                     preg_match_all('/([^;:\s]*):([^;]*)/', $tag['attribute']['style'], $style_array, PREG_PATTERN_ORDER);
    177:                     $astyle = array();
    178:                     while (list($id, $name) = each($style_array[1])) {
    179:                         $name = mb_strtolower($name);
    180:                         $astyle[$name] = trim($style_array[2][$id]);
    181:                     }
    182:                     if (isset($astyle['color'])) {
    183:                         $this->HREF['color'] = $this->convertHTMLColorToDec($astyle['color']);
    184:                     }
    185:                     if (isset($astyle['text-decoration'])) {
    186:                         $this->HREF['style'] = '';
    187:                         $decors = explode(' ', mb_strtolower($astyle['text-decoration']));
    188:                         foreach ($decors as $dec) {
    189:                             $dec = trim($dec);
    190:                             if (!$this->empty_string($dec)) {
    191:                                 if ($dec{0} == 'u') {
    192:                                     $this->HREF['style'] .= 'U';
    193:                                 } elseif ($dec{0} == 'l') {
    194:                                     $this->HREF['style'] .= 'D';
    195:                                 }
    196:                             }
    197:                         }
    198:                     }
    199:                 }
    200:                 break;
    201:             }
    202:             case 'img': {
    203:                 if (isset($tag['attribute']['src'])) {
    204:                     // replace relative path with real server path
    205:                     if ($tag['attribute']['src'][0] == '/') {
    206:                         $tag['attribute']['src'] = $_SERVER['DOCUMENT_ROOT'].$tag['attribute']['src'];
    207:                     }
    208:
    209:                     $tag['attribute']['src'] = urldecode($tag['attribute']['src']);
    210:
    211:                     if (!isset($tag['attribute']['width'])) {
    212:                         $tag['attribute']['width'] = 0;
    213:                     }
    214:                     if (!isset($tag['attribute']['height'])) {
    215:                         $tag['attribute']['height'] = 0;
    216:                     }
    217:
    218:                     $tag['attribute']['align'] = 'bottom';
    219:
    220:                     switch($tag['attribute']['align']) {
    221:                         case 'top': {
    222:                         $align = 'T';
    223:                             break;
    224:                         }
    225:                         case 'middle': {
    226:                             $align = 'M';
    227:                             break;
    228:                         }
    229:                         case 'bottom': {
    230:                             $align = 'B';
    231:                             break;
    232:                         }
    233:                         default: {
    234:                             $align = 'B';
    235:                             break;
    236:                         }
    237:                     }
    238:                     $fileinfo = pathinfo($tag['attribute']['src']);
    239:                     if (isset($fileinfo['extension']) AND (!$this->empty_string($fileinfo['extension']))) {
    240:                         $type = mb_strtolower($fileinfo['extension']);
    241:                     }else{
    242:                         $type = '';
    243:                     }
    244:                     $prevy = $this->y;
    245:                     $xpos = $this->GetX();
    246:                     if (isset($dom[($key - 1)]) AND ($dom[($key - 1)]['value'] == ' ')) {
    247:                         if ($this->rtl) {
    248:                             $xpos += $this->GetStringWidth(' ');
    249:                         } else {
    250:                             $xpos -= $this->GetStringWidth(' ');
    251:                         }
    252:                     }
    253:                     $imglink = '';
    254:                     if (isset($this->HREF['url']) AND !$this->empty_string($this->HREF['url'])) {
    255:                         $imglink = $this->HREF['url'];
    256:                         if ($imglink{0} == '#') {
    257:                             // convert url to internal link
    258:                             $page = intval(mb_substr($imglink, 1));
    259:                             $imglink = $this->AddLink();
    260:                             $this->SetLink($imglink, 0, $page);
    261:                         }
    262:                     }
    263:                     $border = 0;
    264:                     if (isset($tag['attribute']['border']) AND !empty($tag['attribute']['border'])) {
    265:                         // currently only support 1 (frame) or a combination of 'LTRB'
    266:                         $border = $tag['attribute']['border'];
    267:                     }
    268:                     if (isset($tag['attribute']['width'])) {
    269:                         $iw = $this->getHTMLUnitToUnits($tag['attribute']['width'], 1, 'px', false);
    270:                     }
    271:                     if (isset($tag['attribute']['height'])) {
    272:                         $ih = $this->getHTMLUnitToUnits($tag['attribute']['height'], 1, 'px', false);
    273:                     }
    274:                     if (($type == 'eps') OR ($type == 'ai')) {
    275:                         $this->ImageEps($tag['attribute']['src'], $xpos, $this->GetY(), $iw, $ih, $imglink, true, $align, '', $border);
    276:                     } else {
    277:                         $this->Image($tag['attribute']['src'], $xpos, $this->GetY(), $iw, $ih, '', $imglink, $align, false, 300, '', false, false, $border);
    278:                     }
    279:                     switch($align) {
    280:                         case 'T': {
    281:                             $this->y = $prevy;
    282:                             break;
    283:                         }
    284:                         case 'M': {
    285:                             $this->y = (($this->img_rb_y + $prevy - ($tag['fontsize'] / $this->k)) / 2) ;
    286:                             break;
    287:                         }
    288:                         case 'B': {
    289:                             $this->y = $this->img_rb_y - ($tag['fontsize'] / $this->k);
    290:                             break;
    291:                         }
    292:                     }
    293:                 }
    294:                 break;
    295:             }
    296:             case 'dl': {
    297:                 ++$this->listnum;
    298:                 $this->addHTMLVertSpace(0, $cell, '', $firstorlast, $tag['value'], false);
    299:                 break;
    300:             }
    301:             case 'dt': {
    302:                 $this->addHTMLVertSpace(1, $cell, '', $firstorlast, $tag['value'], false);
    303:                 break;
    304:             }
    305:             case 'dd': {
    306:                 if ($this->rtl) {
    307:                     $this->rMargin += $this->listindent;
    308:                 } else {
    309:                     $this->lMargin += $this->listindent;
    310:                 }
    311:                 $this->addHTMLVertSpace(1, $cell, '', $firstorlast, $tag['value'], false);
    312:                 break;
    313:             }
    314:             case 'ul':
    315:             case 'ol': {
    316:                 $this->addHTMLVertSpace(0, $cell, '', $firstorlast, $tag['value'], false);
    317:                 $this->htmlvspace = 0;
    318:                 ++$this->listnum;
    319:                 if ($tag['value'] == 'ol') {
    320:                     $this->listordered[$this->listnum] = true;
    321:                 } else {
    322:                     $this->listordered[$this->listnum] = false;
    323:                 }
    324:                 if (isset($tag['attribute']['start'])) {
    325:                     $this->listcount[$this->listnum] = intval($tag['attribute']['start']) - 1;
    326:                 } else {
    327:                     $this->listcount[$this->listnum] = 0;
    328:                 }
    329:                 if ($this->rtl) {
    330:                     $this->rMargin += $this->listindent;
    331:                 } else {
    332:                     $this->lMargin += $this->listindent;
    333:                 }
    334:                 $this->addHTMLVertSpace(0, $cell, '', $firstorlast, $tag['value'], false);
    335:                 $this->htmlvspace = 0;
    336:                 break;
    337:             }
    338:             case 'li': {
    339:                 $this->addHTMLVertSpace(1, $cell, '', $firstorlast, $tag['value'], false);
    340:                 if ($this->listordered[$this->listnum]) {
    341:                     // ordered item
    342:                     if (isset($parent['attribute']['type']) AND !$this->empty_string($parent['attribute']['type'])) {
    343:                         $this->lispacer = $parent['attribute']['type'];
    344:                     } elseif (isset($parent['listtype']) AND !$this->empty_string($parent['listtype'])) {
    345:                         $this->lispacer = $parent['listtype'];
    346:                     } elseif (isset($this->lisymbol) AND !$this->empty_string($this->lisymbol)) {
    347:                         $this->lispacer = $this->lisymbol;
    348:                     } else {
    349:                         $this->lispacer = '#';
    350:                     }
    351:                     ++$this->listcount[$this->listnum];
    352:                     if (isset($tag['attribute']['value'])) {
    353:                         $this->listcount[$this->listnum] = intval($tag['attribute']['value']);
    354:                     }
    355:                 } else {
    356:                     // unordered item
    357:                     if (isset($parent['attribute']['type']) AND !$this->empty_string($parent['attribute']['type'])) {
    358:                         $this->lispacer = $parent['attribute']['type'];
    359:                     } elseif (isset($parent['listtype']) AND !$this->empty_string($parent['listtype'])) {
    360:                         $this->lispacer = $parent['listtype'];
    361:                     } elseif (isset($this->lisymbol) AND !$this->empty_string($this->lisymbol)) {
    362:                         $this->lispacer = $this->lisymbol;
    363:                     } else {
    364:                         $this->lispacer = '!';
    365:                     }
    366:                 }
    367:                 break;
    368:             }
    369:             case 'blockquote': {
    370:                 if ($this->rtl) {
    371:                     $this->rMargin += $this->listindent;
    372:                 } else {
    373:                     $this->lMargin += $this->listindent;
    374:                 }
    375:                 $this->addHTMLVertSpace(2, $cell, '', $firstorlast, $tag['value'], false);
    376:                 break;
    377:             }
    378:             case 'br': {
    379:                 $this->Ln('', $cell);
    380:                 break;
    381:             }
    382:             case 'div': {
    383:                 $this->addHTMLVertSpace(1, $cell, '', $firstorlast, $tag['value'], false);
    384:                 break;
    385:             }
    386:             case 'p': {
    387:                 $this->addHTMLVertSpace(2, $cell, '', $firstorlast, $tag['value'], false);
    388:                 break;
    389:             }
    390:             case 'pre': {
    391:                 $this->addHTMLVertSpace(1, $cell, '', $firstorlast, $tag['value'], false);
    392:                 $this->premode = true;
    393:                 break;
    394:             }
    395:             case 'sup': {
    396:                 $this->SetXY($this->GetX(), $this->GetY() - ((0.7 * $this->FontSizePt) / $this->k));
    397:                 break;
    398:             }
    399:             case 'sub': {
    400:                 $this->SetXY($this->GetX(), $this->GetY() + ((0.3 * $this->FontSizePt) / $this->k));
    401:                 break;
    402:             }
    403:             case 'h1':
    404:             case 'h2':
    405:             case 'h3':
    406:             case 'h4':
    407:             case 'h5':
    408:             case 'h6': {
    409:                 $this->addHTMLVertSpace(1, $cell, ($tag['fontsize'] * 1.5) / $this->k, $firstorlast, $tag['value'], false);
    410:             break;
    411:             }
    412:             case 'tcpdf': {
    413:                 // NOT HTML: used to call TCPDF methods
    414:                 if (isset($tag['attribute']['method'])) {
    415:                     $tcpdf_method = $tag['attribute']['method'];
    416:                     if (method_exists($this, $tcpdf_method)) {
    417:                         if (isset($tag['attribute']['params']) AND (!empty($tag['attribute']['params']))) {
    418:                             eval('$params = array('.$tag['attribute']['params'].');');
    419:                             call_user_func_array(array($this, $tcpdf_method), $params);
    420:                         } else {
    421:                             $this->$tcpdf_method();
    422:                         }
    423:                         $this->newline = true;
    424:                     }
    425:                 }
    426:             }
    427:             default: {
    428:                 break;
    429:             }
    430:         }
    431:     }
    432: }
    433:
    434: ?>