File Manager

Current Path : /webspace/www.saveursetterroir.be/html/modules/CGSmartImage/lib/
Upload File :
Current File : /webspace/www.saveursetterroir.be/html/modules/CGSmartImage/lib/class.cgsi_utils.php

<?php
#BEGIN_LICENSE
#-------------------------------------------------------------------------
# Module: CGSmartImage (c) 2012 by Robert Campbell (calguy1000@cmsmadesimple.org)
#
#  An addon module for CMS Made Simple to allow creating image tags in a smart
#  way to optimize performance.
#
#-------------------------------------------------------------------------
# CMS - CMS Made Simple is (c) 2005-2010 by Ted Kulp (wishy@cmsmadesimple.org)
# This projects homepage is: http://www.cmsmadesimple.org
#
#-------------------------------------------------------------------------
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# However, as a special exception to the GPL, this software is distributed
# as an addon module to CMS Made Simple.  You may not use this software
# in any Non GPL version of CMS Made simple, or in any version of CMS
# Made simple that does not indicate clearly and obviously in its admin
# section that the site was built with CMS Made simple.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
# Or read it online: http://www.gnu.org/licenses/licenses.html#GPL
#
#-------------------------------------------------------------------------
#END_LICENSE

final class cgsi_utils
{
    protected function __construct() {}
    static private $_device_data;

    /**
     * Given a fairly loose image type identifier (either an extension, or a mime type that could be somewhat mis-spelled
     * attempt to return a reasonable mime type
     */
    private static function parse_type($str,$dflt = 'image/png')
    {
        $str = strtolower($str);
        while( startswith($str,'.') ) $str = substr($str,1);

        switch( $str ) {
        case 'image/jpeg':
        case 'image/png':
        case 'image/gif':
        case 'image/bmp':
        case 'image/webp':
            return $str;
        case 'image/x-windows-bmp':
        case 'image/x-ms-bmp':
            return 'image/bmp';
        case 'image/jpg':
        case 'jpeg':
        case 'jpg':
            return 'image/jpeg';
        case 'png':
            return 'image/png';
        case 'gif':
            return 'image/gif';
        case 'bmp':
            return 'image/bmp';
        case 'webp':
            return 'image/webp';
        default:
            return $dflt;
        }
    }

    /**
     * Given a mime type for or known image formats, return an extension
     */
    private static function get_extension($mime_type)
    {
        $map = array('image/jpeg'=>'.jpg',
                     'image/png'=>'.png',
                     'image/bmp'=>'.bmp',
                     'image/gif'=>'.gif');
        if( isset($map[$mime_type]) ) return $map[$mime_type];
    }

    /**
     * Return the options for a particular alias
     */
    private static function _get_alias_options($name)
    {
        static $aliases;
        if( !$aliases ) {
            $mod = cms_utils::get_module('CGSmartImage');
            $tmp = $mod->GetPreference('aliases');
            $aliases = 'FALSE';
            if( $tmp ) $aliases = unserialize($tmp);
        }
        if( is_array($aliases) ) {
            $keys = array_keys($aliases);
            for( $i = 0; $i < count($keys); $i++ ) {
                $key = $keys[$i];
                if( $aliases[$key]['name'] == $name ) return $aliases[$key]['options'];
            }
        }
    }

    private static function _expand_quoted_string($str)
    {
        $result = array();
        $col = '';
        $safe = '';
        $prev_char = '';
        for( $i = 0; $i < strlen($str); $i++ ) {
            switch( $str[$i] ) {
            case ' ':
                if( !$safe ) {
                    if( strpos($col,'=') !== FALSE ) {
                        list($k,$v) = explode('=',$col,2);
                        $result[$k] = $v;
                    }
                    $col = '';
                }
                else {
                    $col .= $str[$i];
                }
                break;

            case "'":
            case '"':
                if( $prev_char != '\\' ) {
                    if( $str[$i] == $safe ) {
                        $safe = null;
                    }
                    else {
                        $safe = $str[$i];
                    }
                }
            break;

            default:
                $col .= $str[$i];
                break;
            }

            $prev_char = $str[$i];
        }

        if( strlen($col) != 0 ) {
            if( strpos($col,'=') !== FALSE ) {
                list($k,$v) = explode('=',$col,2);
                $result[$k] = $v;
            }
        }

        return $result;
    }


    private static function _is_stylesheet()
    {
        $tmp = debug_backtrace();
        foreach( $tmp as $elem ) {
            if( isset($elem['function']) && $elem['function'] == 'smarty_cms_function_cms_stylesheet' ) return TRUE;
        }
        return FALSE;
    }


    public static function color_to_rgb($str)
    {
        $str = trim($str);
        $res = array(0,0,0);

        if( startswith($str,'#') && strlen($str) == 4 ) {
            $r = substr($str,1,1); $r = $r.$r;
            $g = substr($str,2,1); $g = $g.$g;
            $b = substr($str,3,1); $b = $b.$b;
            $res[0] = hexdec($r);
            $res[1] = hexdec($g);
            $res[2] = hexdec($b);
            return $res;
        }

        if( startswith($str,'#') && strlen($str) == 7 ) {
            $res[0] = hexdec(substr($str,1,2));
            $res[1] = hexdec(substr($str,3,2));
            $res[2] = hexdec(substr($str,5,2));
            return $res;
        }

        $tmp = explode(':',$str,3);
        if( is_array($tmp) && count($tmp) == 3 && is_numeric($tmp[0]) && is_numeric($tmp[1]) && is_numeric($tmp[1]) ) {
            $res[0] = (int)$tmp[0];
            $res[1] = (int)$tmp[1];
            $res[2] = (int)$tmp[2];
            return $res;
        }

        // assume it's a color name.
        static $_colors;
        if( !is_array($_colors) ) {
            $fn = __DIR__.'/colors.dat';
            $data = file($fn);
            if( count($data) ) {
                $_colors = array();
                for( $i = 0; $i < count($data); $i++ ) {
                    list($rgb,$name) = explode('-',$data[$i],2);
                    if( !startswith($rgb,'#') || strlen($rgb) != 7 || $name == '' ) continue;

                    $tmp = array();
                    $tmp[0] = hexdec(substr($rgb,1,2));
                    $tmp[1] = hexdec(substr($rgb,3,2));
                    $tmp[2] = hexdec(substr($rgb,5,2));

                    $_colors[strtolower(trim($name))] = $tmp;
                }
            }
        }
        if( is_array($_colors) && isset($_colors[$str]) ) $res = $_colors[$str];
        return $res;
    }

    public static function &process_image($params)
    {
        $mod = cms_utils::get_module('CGSmartImage');
        $config = cmsms()->GetConfig();
        $want_transform = 0;
        $do_transform = 0;
        $have_transform = 0;
        $dest_fname = '';
        $dest_url = '';
        $img = '';
        $srcfile = '';
        $rel = 0;
        $outp = array();  // output params
        $outp['id'] = '';
        $outp['name'] = '';
        $outp['class'] = '';
        $outp['style'] = '';
        $outp['src'] = '';
        $outp['width'] = '';
        $outp['height'] = '';
        $outp['error'] = '';
        $opp = array();  // operation params
        $opp['overwrite'] = 0;
        $opp['nobcache'] = 0;
        $opp['noremote'] = 0;
        $opp['noembed'] = 0;
        $opp['noauto'] = 0;
        $opp['norotate'] = 0;
        $opp['notimecheck'] = 0;
        $opp['noautoscale'] = 0;
        $opp['notag'] = 0;
        $opp['noresponsive'] = 0;
        $opp['nobreakpoints'] = 0;
        $opp['max_width'] = '';
        $opp['max_height'] = '';
        $opp['src'] = '';
        $opp['quality'] = 75;
        $opp['filters'] = array();
        $opp['force_type'] = '';
        $opp['force_ext'] = $mod->GetPreference('force_extension',0);
        $opp['progressive'] = (int) $mod->GetPreference('progressive',0);
        $srcimgsize = ''; // src image size
        $lastfilter = null;

        try {
            $tmp = $mod->GetPreference('aliases');
            if( $tmp ) $aliases = unserialize($tmp);

            // first pass... expand aliases and build src
            $new_params = array();
            foreach( $params as $key => $value ) {
                if( startswith($key,'alias') ) {
                    // expand alias
                    $options = self::_get_alias_options($value);
                    if( $options ) {
                        // parse a string into an array of arguments.
                        $data = self::_expand_quoted_string($options);
                        if( is_array($data) ) {
                            foreach( $data as $key => $value ) {
                                $new_params[$key] = $value;
                            }
                        }
                        continue;
                    }
                }
                elseif( startswith($key,'src') && $key != 'src' ) {
                    // handle src1 through src99 arguments.
                    if( !isset($new_params['src']) ) $new_params['src'] = '';
                    if( !empty($new_params['src']) && !endswith($new_params['src'],'/') ) $new_params['src'] .= '/';
                    $new_params['src'] .= $value;
                    continue;
                }

                // everything else just gets added.
                $new_params[$key] = $value;
            }
            $params = $new_params;

            // second pass, build our arrays
            $parse_params = function($parms, $depth = 0) use( &$parse_params, &$opp, &$outp ) {
                foreach( $parms as $key => $value ) {
                    $matches = array();
                    if( preg_match('/^filter_[0-9]._/',$key,$matches) ) {
                        $key = substr($key,strlen($matches[0]));
                        $filter = ucwords($key);
                        $args = explode(',',$value);
                        $classname = 'CGImage_'.$filter.'_Filter';
                        if( !class_exists($classname) ) throw new Exception($mod->Lang('error_unknownfilter',$filter));

                        // add it to the ops.
                        $opp['filters'][] = array($classname,$args);
                        // done.
                        continue;
                    }

                    if( startswith($key,'filter_') ) {
                        // handle filter argument.
                        $filter = ucwords(substr($key,strlen('filter_')));
                        $args = explode(',',$value);
                        $classname = 'CGImage_'.$filter.'_Filter';
                        if( !class_exists($classname) ) throw new Exception($mod->Lang('error_unknownfilter',$filter));

                        // add it to the ops.
                        $opp['filters'][] = array($classname,$args);
                        // done.
                        continue;
                    }

                    switch( $key ) {
                    case 'data':
                    if( $depth == 0 ) $parse_params($value,$depth+1);
                    break;

                    case 'class':
                    case 'id':
                    case 'style':
                    case 'name':
                    case 'alt':
                    case 'rel':
                    case 'title':
                    $outp[$key] = trim($value);
                    break;

                    case 'width':
                    case 'height':
                    $outp[$key] = (int)$value;
                    break;

                    case 'max_width':
                    case 'max_height':
                    $opp[$key] = (int)$value;
                    break;

                    case 'src':
                    case 'force_type':
                    $opp[$key] = trim($value);
                    break;

                    case 'quality':
                    $opp['quality'] = (int)$value;
                    $opp['quality'] = min(100,max(0,$opp['quality']));
                    break;

                    case 'overwrite':
                    case 'notag':
                    case 'noremote':
                    case 'noresponsive':
                    case 'nobreakpoints':
                    case 'nobcache':
                    case 'noembed':
                    case 'noauto':
                    case 'norotate':
                    case 'notimecheck':
                    case 'force_ext':
                    case 'progressive':
                    $opp[$key] = cge_utils::to_bool($value);
                    break;
                    }
                }
            };

            $parse_params($params);

            if( !$opp['src'] ) throw new Exception($mod->Lang('error_missingparam','src'));

            //
            // find the source image ... the actual filename
            // use some automagic intelligence to find it.
            //
            $opp['src'] = urldecode($opp['src']);
            if( !$srcfile && startswith($opp['src'],$config['uploads_url']) ) {
                $tmp = str_replace($config['uploads_url'],$config['uploads_path'],$opp['src']);
                if( file_exists($tmp) ) $srcfile = $tmp;
            }
            if( !$srcfile && startswith($opp['src'],$config['root_url']) ) {
                $tmp = str_replace($config['root_url'],$config['root_path'],$opp['src']);
                if( file_exists($tmp) ) $srcfile = $tmp;
            }
            if( !$srcfile && isset($config['ssl_url']) && startswith($opp['src'],$config['ssl_url']) ) {
                $tmp = str_replace($config['ssl_url'],$config['root_path'],$opp['src']);
                if( file_exists($tmp) ) $srcfile = $tmp;
            }
            if( !$srcfile && startswith($opp['src'],'/') ) {
                $rp1 = realpath($config['root_path']);
                $rp2 = realpath($opp['src']);
                if( startswith($rp2,$rp1) && file_exists($opp['src']) ) $srcfile = $opp['src'];
            }
            if( !$srcfile ) {
                // check relative path wrt the uploads dir.
                $tmp = cms_join_path($config['uploads_path'],$opp['src']);
                $rp1 = realpath($config['uploads_path']);
                $rp2 = realpath($tmp);
                if( startswith($rp2,$rp1) && file_exists($tmp) ) $srcfile = $tmp;
            }
            if( !$srcfile ) {
                // check relative path wrt the root dir.
                $tmp = cms_join_path($config['root_path'],$opp['src']);
                $rp1 = realpath($config['root_path']);
                $rp2 = realpath($tmp);
                if( startswith($rp2,$rp1) && file_exists($tmp) ) $srcfile = $tmp;
            }
            if( !$srcfile && $opp['noremote'] == 0 &&
                (startswith($opp['src'],'http:') || startswith($opp['src'],'https:') || startswith($opp['src'],'ftp:'))) {
                // okay, gotta assume that ths is a remote file
                // get it, and cache it.
                $cachefile = TMP_CACHE_LOCATION.'/cgsi_'.md5($opp['src']).'.img';
                if( !file_exists($cachefile) ) {
                    $data = file_get_contents($opp['src']);
                    if( $data ) {
                        file_put_contents($cachefile,$data);
                        $srcfile = $cachefile;
                    }
                }
                else {
                    $srcfile = $cachefile;
                }
            }

            if( !$srcfile ) {
                throw new Exception($mod->Lang('error_srcnotfound',$opp['src']));
                return $outp;
            }

            // get the source image size
            $srcinfo = getimagesize($srcfile);
            if( !is_array($srcinfo) || count($srcinfo) < 2 ) {
                throw new Exception($mod->Lang('error_srcnotfound',$opp['src']));
            }
            else {
                $srcimgsize = array('width'=>$srcinfo[0],'height'=>$srcinfo[1]);
                $memory_needed = round( $srcinfo[0] * $srcinfo[1]
                                        * (isset($srcinfo['bits'])?$srcinfo['bits']:8)
                                        * (isset($srcinfo['channels'])?$srcinfo['channels']:3) / 8 + 65535 );
                if( $mod->GetPreference('checkmemory',1) && !cge_utils::have_enough_memory($memory_needed) ) {
                    throw new Exception($mod->Lang('error_insufficientmemory').': '.(int)($memory_needed/1024).'k');
                }
            }

            // are we automagically rotating.
            if( !$opp['norotate'] && function_exists('exif_read_data') ) {
                // if there is already a rotate filter in the list, we won't override that.
                $fn = 0;
                for( $f = 0; $f < count($opp['filters']); $f++ ) {
                    if( $opp['filters'][$f][0] == 'CGImage_Rotate_Filter' ) {
                        $fn = 1;
                        break;
                    }
                }

                if( $fn == 0 ) {
                    // we can try to read the exif information to find an orientation.
                    $exif = @exif_read_data($srcfile,0,TRUE);
                    if( is_array($exif) && isset($exif['IFD0']) && isset($exif['IFD0']['Orientation']) &&
                        is_int($exif['IFD0']['Orientation']) ) {

                        // found an orientation, now we gotta figure out what filters to add.
                        $orientation = (int)$exif['IFD0']['Orientation'];
                        $new_filters = array();
                        switch( $orientation ) {
                        case 1:
                            // nothing.
                            break;
                        case 2:
                            // horizontal flip.
                            $new_filters[] = array('CGImage_Flip_Filter',0);
                            break;
                        case 3:
                            // rotate 180
                            $new_filters[] = array('CGImage_Rotate_Filter',array(180));
                            break;
                        case 4:
                            $new_filters[] = array('CGImage_Flip_Filter',1);
                            break;
                        case 5:
                            $new_filters[] = array('CGImage_Flip_Filter',1);
                            $new_filters[] = array('CGImage_Rotate_Filter',array(90));
                            break;
                        case 6:
                            $new_filters[] = array('CGImage_Rotate_Filter',array(90));
                            break;
                        case 7:
                            $new_filters[] = array('CGImage_Flip_Filter',0);
                            $new_filters[] = array('CGImage_Rotate_Filter',array(90));
                            break;
                        case 8:
                            $new_filters[] = array('CGImage_Rotate_Filter',array(-90));
                            break;
                        }

                        $opp['filters'] = array_merge($new_filters,$opp['filters']);
                    }
                }
            }

            // doing responsive images... get device width and height.
            $is_responsive = 0;
            if( $mod->GetPreference('responsive',0) && $opp['noresponsive'] == 0 ) {
                $device = self::get_device_capabilities();
                if( is_array($device) && isset($device['width']) && isset($device['height']) ) {
                    // we found device capabilities.

                    // we have to do auto-scaling now, responsive stuff trumps it.
                    $opp['noautoscale'] = 0;
                    $is_responsive = 1;

                    // merge that data with any max_width and max_height that have already been supplied.
                    $w = max(1,(int)$device['width']);
                    if( $opp['max_width'] > 0 ) {
                        $opp['max_width'] = min($opp['max_width'],$w);
                    }
                    else {
                        $opp['max_width'] = $w;
                    }

                    $h = max(1,(int)$device['height']);
                    if( $opp['max_height'] > 0 ) {
                        $opp['max_height'] = min($opp['max_height'],$h);
                    }
                    else {
                        $opp['max_height'] = $h;
                    }
                }
            }

            // rationalize width/height, max_width, max_height
            $no_width_height = 0;
            if( $opp['max_width'] && $outp['width'] ) {
                $no_width_height = 1;
                $opp['max_width'] = min($opp['max_width'],$outp['width']);
            }
            if( $opp['max_height'] && $outp['height'] ) {
                $no_width_height = 1;
                $opp['max_height'] = min($opp['max_height'],$outp['height']);
            }

            // now do some intelligence, and see if the width, and height arguments passed in
            // match the image size... if not, and max_width/height aren't already smaller... add a filter.
            if( $no_width_height == 0 && ($outp['width'] > 0 || $outp['height'] > 0) && $opp['noautoscale'] == 0 ) {
                if( $outp['width'] != $srcimgsize['width'] || $outp['height'] != $srcimgsize['height'] ) {
                    // we wanna display the file at a different dimenion.
                    $args = '';
                    $filter = '';
                    if( $outp['width'] && $outp['height'] ) {
                        // gonna do a crop to fit
                        $filter = 'CGImage_Croptofit_Filter';
                        $args = array((int)$outp['width'],(int)$outp['height']);
                    }
                    else if( $outp['width'] ) {
                        // gonna do a resize
                        $filter = 'CGImage_Resize_Filter';
                        $args = array('w',(int)$outp['width']);
                    }
                    else if ( $outp['height'] ) {
                        // gonna do a resize
                        $filter = 'CGImage_Resize_Filter';
                        $args = array('h',(int)$outp['height']);
                    }
                    if( is_array($args) && $filter != '' ) {
                        $found = 0;
                        for( $i = 0; $i < count($opp['filters']); $i++ ) {
                            if( $opp['filters'][$i][0] == 'CGImage_Resize_Filter' ) {
                                $found = 1;
                                break;
                            }
                        }
                        // add a filter to the end
                        if( !$found ) $lastfilter = array($filter,$args);
                    }
                }
            }

            // if we are forcing a type and that type is not the same as our current type.
            if( $opp['force_type'] ) {
                $tmp_a = self::parse_type($opp['force_type']);
                if( $tmp_a != $srcinfo['mime'] ) $want_transform = 1;
            }

            // if we have max width and/or height... add a filter at the end
            // to make sure that our output never exceeds those max values.
            if( ($opp['max_width'] > 0 || $opp['max_height'] > 0) && $opp['noautoscale'] == 0 ) {
                // if we have breakpoints, use find the closest one
                $args = '';
                $filter = '';
                $bp = null;

                if( ($tmp = $mod->GetPreference('responsive_breakpoints')) && $is_responsive == 1 &&
                    !$opp['nobreakpoints'] ) {
                    $tmp = explode(',',$tmp);
                    $bp = array();
                    for( $i = 0; $i < count($tmp); $i++ ) {
                        $t1 = (int)trim($tmp[$i]);
                        if( $t1 > 0 ) $bp[] = $t1;
                    }
                    asort($bp);
                }

                if( is_array($bp) && count($bp) ) {
                    // we have valid breakpoints.
                    $lval = max($opp['max_width'],$opp['max_height']);
                    for( $i = count($bp)-1; $i > 0; $i-- ) {
                        if( $bp[$i] > $lval ) continue;
                        break;
                    }

                    // resize to maximum dimension of lval
                    // note, it'd be nice to have some kind of settings here
                    // i.e: which filer (and other params) to use.
                    $lval = $bp[$i];
                    $filter = 'CGImage_Resize_Filter';
                    $args = array('e',$lval,0);
                }
                else {
                    // standard handling of max width/max height.
                    if( $opp['max_width'] && $opp['max_height'] ) {
                        $filter = 'CGImage_Croptofit_Filter';
                        $args = array((int)$opp['max_width'],(int)$opp['max_height']);
                    }
                    else if( $opp['max_width'] ) {
                        $filter = 'CGImage_Resize_Filter';
                        $args = array('w',(int)$opp['max_width'],0);
                    }
                    else if( $opp['max_height'] ) {
                        $filter = 'CGImage_Resize_Filter';
                        $args = array('h',(int)$opp['max_height'],0);
                    }
                }
                // adjust our lastfilter
                if( $filter ) $lastfilter = array($filter,$args);
            }

            // if we have a last filter... add it.
            if( $lastfilter ) $opp['filters'][] = $lastfilter;

            //
            // end of smartness stuff... now begin the work
            //
            if( count(array_keys($opp['filters'])) ) $want_transform = 1; // we're doing some kind of magic to the image.

            if( $want_transform ) {
                // calculate our destination name and url.
                $tmp = basename($srcfile);
                if( !isset($outp['alt']) ) $outp['alt'] = $tmp;
                $ext = strrchr($tmp,'.');
                $t2 = md5(serialize($opp));
                $destname = 'img-'.$t2;
                $t3 = self::parse_type(($opp['force_type'])?$opp['force_type']:$srcinfo['mime']);
                if( $opp['force_ext'] ) $destname .= self::get_extension($t3);

                $cache_path = $mod->GetPreference('cache_path', cms_join_path('uploads', '_'.$mod->GetName()));
                $destdir = cms_join_path($config['root_path'], $cache_path);
                if( !is_dir($destdir) ) {
                    @mkdir($destdir, 0777, true);
                    touch($destdir.'/index.html');
                }

                if( !is_dir($destdir) ) throw new Exception($mod->Lang('error_mkdir',$destdir));

                // see if it exists
                $dest_fname = $destdir.'/'.$destname;

                $dest_url = $mod->get_cached_image_url($destname);
                $t1 = filemtime($srcfile);
                $t2 = file_exists($dest_fname) ? filemtime($dest_fname) : 0;
                if( !file_exists($dest_fname) || (($t2 < $t1) && !$opp['notimecheck']) || $opp['overwrite']  ) $do_transform = 1;
            }
            else {
                // no transofmration... just use the src image
                $dest_fname = $srcfile;
                $dest_url = $opp['src'];
            }

            if( $do_transform ) {
                try {
                    // load the image.
                    $img = new CGImageBase($srcfile);

                    // process filters
                    $i = 0;
                    while( $i < count($opp['filters']) ) {
                        $filter = $opp['filters'][$i][0];
                        $filter_obj = new $filter($opp['filters'][$i][1]);
                        $img = $filter_obj->transform($img);
                        $img['dirty'] = 1; // force the image dirty, just so that we can save it.
                        $i++;
                    }

                    // check some stuff
                    if( $opp['noauto'] == 0 && (($outp['width'] && $img['width'] < $outp['width']) ||
                                                ($outp['height'] && $img['height'] < $outp['height'])) ) {
                        // user specified a width, and/or height...but they are smaller than the output of the filtering.
                        // this will ensure that the tag will match the image.
                        $outp['width'] = $img['width'];
                        $outp['height'] = $img['height'];
                    }

                    // and write the thing.
                    if( is_object($img) ) {
                        if( $opp['force_type'] ) $img['type'] = self::parse_type($opp['force_type']);
                        if( $img['dirty'] ) $img->save($dest_fname,$opp['quality'],$opp['progressive']);
                    }
                }
                catch( Exception $e ) {
                    audit('','CGSmartImage','Error encountered on '.$opp['src'].': '.$e->GetMessage());
                    throw $e;
                }
            } // if

            // now, we have a cached filename ... need to get its dimensions.
            // and make sure that we're never outputting anything bigger than the cached dimensions
            // unless noauto is set
            if( $opp['noauto'] == 0 ) {
                $tmp = getimagesize($dest_fname);
                if( !is_array($tmp) || count($tmp) < 2 ) throw new Exception($mod->Lang('error_destnotfound',$dest_fname));
                $t_width = $tmp[0]; $t_height = $tmp[1];
                if( ($outp['width'] && $t_width < $outp['width']) || ($outp['height'] && $t_height < $outp['height']) ) {
                    $outp['width'] = $t_width;
                    $outp['height'] = $t_height;
                }
            }

            // at this point, we're ready to handle building the tag.
            if( $opp['nobcache'] ) $dest_url .= '?x='.time();

            if( !isset($outp['alt']) ) {
                if( $dest_fname ) {
                    $outp['alt'] = basename($dest_fname);
                }
                else if( $srcfile ) {
                    $outp['alt'] = basename($srcfile);
                }
                else {
                    $outp['alt'] = basename($opp['src']);
                }
            }

            // build the output.
            if( $opp['notag'] || self::_is_stylesheet() ) {
                $outp['src'] = $dest_url;
                if( !$opp['noembed'] && $mod->can_embed($dest_fname) ) {
                    $type = cge_utils::get_mime_type($dest_fname);
                    if( $type && $type != 'unknown' ) {
                        $tmp = base64_encode(file_get_contents($dest_fname));
                        $outp['src'] = 'data:'.$type.';base64,'.$tmp;
                    }
                }
                else {
                    $outp['src'] = $dest_url;
                }

                if( !isset($outp['output']) ) $outp['output'] = $outp['src'];
            }
            else {
                //
                // gotta build a tag.
                //
                // get the src first.
                if( !$opp['noembed'] && $mod->can_embed($dest_fname) ) {
                    $type = cge_utils::get_mime_type($dest_fname);
                    if( $type && $type != 'unknown' ) {
                        $tmp = base64_encode(file_get_contents($dest_fname));
                        $outp['src'] = 'data:'.$type.';base64,'.$tmp;
                    }
                }

                if( !isset($outp['src']) || !$outp['src'] ) {
                    // fallback to the destination url.
                    $outp['src'] = $dest_url;
                }

                if( $dest_fname && !$opp['noauto'] ) {
                    $details = getimagesize($dest_fname);
                    if( is_array($details) ) {
                        $outp['width']  = (int)$details[0];
                        $outp['height'] = (int)$details[1];
                    }
                }

                // now we can build the tag.
                $output = '<img';
                foreach( $outp as $key => $value ) {
                    if( !$value && $key != 'alt' ) continue; // empty alt is valid... stupid, but valid.
                    $output .= ' '.$key.'="'.$value.'"';
                }
                $output .= '/>';
                $outp['output'] = $output;
            }
        }
        catch( Exception $e ) {
            $outp['error'] = $e->GetMessage();
        }

        // here we're gonna return something
        return $outp;
    }


    public static function cgsi_convert($params,$content,&$smarty,$repeat)
    {
        if( !$content ) return;
        $max_width = -1;
        $max_height = -1;
        if( isset($params['max_height']) ) $max_height = max(0,(int)$params['max_height']);
        if( isset($params['max_width']) ) $max_width = max(0,(int)$params['max_width']);

        $did_modify = FALSE;
        $mod = cms_utils::get_module('CGSmartImage');
        $old_errorval = libxml_use_internal_errors(true);
        $dom = new CGDomDocument();
        $dom->strictErrorChecking = FALSE;
        $dom->validateOnParse = FALSE;
        if( function_exists('mb_convert_encoding') ) $content = mb_convert_encoding($content, 'HTML-ENTITIES', 'UTF-8');
        $dom->loadHTML($content);

        $imgs = $dom->GetElementsByTagName('img');
        if( is_object($imgs) && $imgs->length ) {
            for( $i = 0; $i < $imgs->length; $i++ ) {
                $node = $imgs->item($i);
                $sxe = simplexml_import_dom($node);

                $parms = $params;
                $process = true;
                foreach( $sxe->attributes() as $name => $value ) {
                    $value = (string)$value;
                    if( $value == '' ) continue;

                    switch( $name ) {
                    case 'width':
                        if( $max_width > 0 ) $value = min($max_width,(int)$value);
                        break;

                    case 'height':
                        if( $max_height > 0 ) $value = min($max_height,(int)$value);
                        break;

                    case 'class':
                        $words = explode(' ',$value);
                        if( in_array('nocgsi',$words) ) $process = false;
                        break;
                    }
                    $parms[$name] = $value;
                }

                if( !$process ) continue; // found a reason not do to anything with this image.
                if( !isset($parms['src']) ) continue;
                if( startswith($parms['src'],'data:') ) continue;   // already embedded, can't do anything.

                $parms['notag'] = 1;
                $outp = self::process_image($parms);
                foreach( $outp as $key => $value ) {
                    $did_modify = TRUE;
                    switch( $key ) {
                    case 'width':
                    case 'height':
                        $sxe->attributes()->$key = (int)$value;
                        break;
                    case 'src':
                    default:
                        $sxe->attributes()->$key = $value;
                        break;
                    }
                }
            } // for each image
        }

        // get the contents.
        if( $did_modify ) {
            $node = $dom->documentElement;
            $content = $node->innerHTML;
            $content = str_replace(chr(13),'',$content);
            $content = str_replace('&#13;','',$content);
            if( startswith($content,'<html>') ) {
                $content = str_replace('<html>','',$content);
                $content = str_replace('</html>','',$content);
            }
            if( startswith($content,'<body>') ) {
                $content = str_replace('<body>','',$content);
                $content = str_replace('</body>','',$content);
            }
        }
        return $content;
    }


    public static function get_device_capabilities()
    {
        if( is_array(self::$_device_data) ) return self::$_device_data;
        if( !isset($_SERVER['HTTP_USER_AGENT']) ) return;

        $agent = $_SERVER['HTTP_USER_AGENT'];
        $config = cmsms()->GetConfig();
        $ckey = md5($config['root_url'].'CGExtensionsDeviceCapabilitiesCache');

        // cache results for 14 days.
        $handler = new cms_filecache_driver(array('lifetime'=>24*3600*14,'auto_cleaning'=>1,'group'=>__CLASS__));
        $data = array();
        if( $handler->exists($ckey) ) {
            $rawdat = $handler->get($ckey);
            if( $rawdat ) $data = unserialize($rawdat);
        }
        $ukey = md5($agent);
        if( isset($data[$ukey]) ) {
            self::$_device_data = $data[$ukey];
            return $data[$ukey];
        }

        // gotta do a web service request.
        // here we would determine what client to use.
        $mod = cms_utils::get_module('CGSmartImage');
        if( !$mod ) return;

        // instantiate the class and do the request
        $res = null;
        try {
            $client_class = 'cgsi_DeviceAtlasPersonal_client';
            if( !class_exists($client_class) ) return; // no client class found.
            $client_obj = new $client_class($agent);
            if( !is_object($client_obj) ) return; // no client class possible.
            $res = $client_obj->get_device_resolution();
            if( !is_array($res) ) return;

            // got results from web service
            $data[$ukey] = $res;
            $handler->set($ckey,serialize($data));
            self::$_device_data = $res;
        }
        catch( \Exception $e ) {
            self::$_device_data = array();
        }

        return $res;
    }

    public static function trim_to_device($flag,$value)
    {
        $flag = strtolower($flag);
        if( $value > 0 && is_array(self::$_device_data) && isset(self::$_device_data[$flag]) ) {
            return min($value,self::$_device_data[$flag]);
        }
        return $value;
    }

    public static function get_transparent_color(CGImageBase $img)
    {
        if( $img['transparent'] != '' ) return $img['transparent'];
    }

    public static function find_unused_color(CGImageBase $img)
    {
        // dont have a transparency color... so guess one.
        // find a random unused color for transparency.
        $r = $g = $b = 255;
        $found = 0;
        while( $found < 100 ) {
            $r = rand(0,255);
            $g = rand(0,255);
            $b = rand(0,255);
            if( imagecolorexact($img['rsrc'],$r,$g,$b) != -1 ) break;
            $found++;
        }

        if( $found == 50 ) audit('','CGSmartImage','No unused color found');
        return array($r,$g,$b);
    }
}

#
# EOF
#
?>

File Manager Version 1.0, Coded By Lucas
Email: hehe@yahoo.com