function ReadCSS($html) {
    preg_match_all('/<style[^>]*media=["\']([^"\'>]*)["\'].*?<\/style>/is',$html,$m);
    for($i=0; $i<count($m[0]); $i++) {
        if ($this->mpdf->CSSselectMedia && !preg_match('/('.trim($this->mpdf->CSSselectMedia).'|all)/i',$m[1][$i])) { 
            $html = str_replace($m[0][$i],'',$html);
        }
    }
    preg_match_all('/<link[^>]*media=["\']([^"\'>]*)["\'].*?>/is',$html,$m);
    for($i=0; $i<count($m[0]); $i++) {
        if ($this->mpdf->CSSselectMedia && !preg_match('/('.trim($this->mpdf->CSSselectMedia).'|all)/i',$m[1][$i])) { 
            $html = str_replace($m[0][$i],'',$html);
        }
    }

    // mPDF 5.5.02
    // Remove Comment tags <!-- ... --> inside CSS as <style> in HTML document
    // Remove Comment tags /* ...  */ inside CSS as <style> in HTML document
    // But first, we replace upper and mixed case closing style tag with lower
    // case so we can use str_replace later.
    preg_replace('/<\/style>/i', '</style>', $html);
    preg_match_all('/<style.*?>(.*?)<\/style>/si',$html,$m);
    if (count($m[1])) { 
        for($i=0;$i<count($m[1]);$i++) {
            // Remove comment tags 
            $sub = preg_replace('/(<\!\-\-|\-\->)/s',' ',$m[1][$i]);
            $sub = '>'.preg_replace('|/\*.*?\*/|s',' ',$sub).'</style>';
            $html = str_replace('>'.$m[1][$i].'</style>', $sub, $html);
        }
    }


    $html = preg_replace('/<!--mpdf/i','',$html);
    $html = preg_replace('/mpdf-->/i','',$html);
    $html = preg_replace('/<\!\-\-.*?\-\->/s',' ',$html);

    $match = 0; // no match for instance
    $regexp = ''; // This helps debugging: showing what is the REAL string being processed
    $CSSext = array(); 

    //CSS inside external files
    $regexp = '/<link[^>]*rel=["\']stylesheet["\'][^>]*href=["\']([^>"\']*)["\'].*?>/si';
    $x = preg_match_all($regexp,$html,$cxt);
    if ($x) { 
        $match += $x; 
        $CSSext = $cxt[1];
    }

    $regexp = '/<link[^>]*href=["\']([^>"\']*)["\'][^>]*?rel=["\']stylesheet["\'].*?>/si';
    $x = preg_match_all($regexp,$html,$cxt);
    if ($x) { 
        $match += $x; 
        $CSSext = array_merge($CSSext,$cxt[1]);
    }

    // look for @import stylesheets
    //$regexp = '/@import url\([\'\"]{0,1}([^\)]*?\.css)[\'\"]{0,1}\)/si';
    $regexp = '/@import url\([\'\"]{0,1}([^\)]*?\.css(\?\S+)?)[\'\"]{0,1}\)/si';
    $x = preg_match_all($regexp,$html,$cxt);
    if ($x) { 
        $match += $x; 
        $CSSext = array_merge($CSSext,$cxt[1]);
    }

    // look for @import without the url()
    //$regexp = '/@import [\'\"]{0,1}([^;]*?\.css)[\'\"]{0,1}/si';
    $regexp = '/@import [\'\"]{0,1}([^;]*?\.css(\?\S+)?)[\'\"]{0,1}/si';
    $x = preg_match_all($regexp,$html,$cxt);
    if ($x) { 
        $match += $x; 
        $CSSext = array_merge($CSSext,$cxt[1]);
    }

    $ind = 0;
    $CSSstr = '';

    if (!is_array($this->cascadeCSS)) $this->cascadeCSS = array();

    while($match){
        $path = $CSSext[$ind];

        $path = htmlspecialchars_decode($path);    // mPDF 6

        $this->mpdf->GetFullPath($path); 
        $CSSextblock = $this->mpdf->_get_file($path);
        if ($CSSextblock) {
            // look for embedded @import stylesheets in other stylesheets
            // and fix url paths (including background-images) relative to stylesheet
            //$regexpem = '/@import url\([\'\"]{0,1}(.*?\.css)[\'\"]{0,1}\)/si';
            $regexpem = '/@import url\([\'\"]{0,1}(.*?\.css(\?\S+)?)[\'\"]{0,1}\)/si';
            $xem = preg_match_all($regexpem,$CSSextblock,$cxtem);
            $cssBasePath = preg_replace('/\/[^\/]*$/','',$path) . '/';
            if ($xem) { 
                foreach($cxtem[1] AS $cxtembedded) {
                    // path is relative to original stlyesheet!!
                    $this->mpdf->GetFullPath($cxtembedded, $cssBasePath );
                    $match++;
                    $CSSext[] = $cxtembedded;
                }
            }
            $regexpem = '/(background[^;]*url\s*\(\s*[\'\"]{0,1})([^\)\'\"]*)([\'\"]{0,1}\s*\))/si';
            $xem = preg_match_all($regexpem,$CSSextblock,$cxtem);
            if ($xem) { 
                for ($i=0;$i<count($cxtem[0]);$i++) {
                    // path is relative to original stlyesheet!!
                    $embedded = $cxtem[2][$i];
                    if (!preg_match('/^data:image/i', $embedded)) {    // mPDF 5.5.13
                        $this->mpdf->GetFullPath($embedded, $cssBasePath );
                        $CSSextblock = str_replace($cxtem[0][$i], ($cxtem[1][$i].$embedded.$cxtem[3][$i]), $CSSextblock);
                    }
                }
            }
            $CSSstr .= ' '.$CSSextblock;
        }
        $match--;
        $ind++;
    } //end of match

    $match = 0; // reset value, if needed
    // CSS as <style> in HTML document
    $regexp = '/<style.*?>(.*?)<\/style>/si'; 
    $match = preg_match_all($regexp,$html,$CSSblock);
    if ($match) {
        $tmpCSSstr = implode(' ',$CSSblock[1]);
        $regexpem = '/(background[^;]*url\s*\(\s*[\'\"]{0,1})([^\)\'\"]*)([\'\"]{0,1}\s*\))/si';
        $xem = preg_match_all($regexpem,$tmpCSSstr ,$cxtem);
        if ($xem) { 
           for ($i=0;$i<count($cxtem[0]);$i++) {
            $embedded = $cxtem[2][$i];
            if (!preg_match('/^data:image/i', $embedded)) {    // mPDF 5.5.13
                $this->mpdf->GetFullPath($embedded);
                $tmpCSSstr = str_replace($cxtem[0][$i], ($cxtem[1][$i].$embedded.$cxtem[3][$i]), $tmpCSSstr );
            }
           }
        }
        $CSSstr .= ' '.$tmpCSSstr;
    }
    // Remove comments
    $CSSstr = preg_replace('|/\*.*?\*/|s',' ',$CSSstr);
    $CSSstr = preg_replace('/[\s\n\r\t\f]/s',' ',$CSSstr);

    if (preg_match('/@media/',$CSSstr)) { 
        preg_match_all('/@media(.*?)\{(([^\{\}]*\{[^\{\}]*\})+)\s*\}/is',$CSSstr,$m);
        for($i=0; $i<count($m[0]); $i++) {
            if ($this->mpdf->CSSselectMedia && !preg_match('/('.trim($this->mpdf->CSSselectMedia).'|all)/is',$m[1][$i])) { 
                $CSSstr = str_replace($m[0][$i], '', $CSSstr);
            }
            else {
                $CSSstr = str_replace($m[0][$i],' '.$m[2][$i].' ',$CSSstr);
            }
        }
    }

    // mPDF 5.5.13
    // Replace any background: url(data:image... with temporary image file reference
    preg_match_all("/(url\(data:image\/(jpeg|gif|png);base64,(.*?)\))/si", $CSSstr, $idata);    // mPDF 5.7.2
    if (count($idata[0])) { 
        for($i=0;$i<count($idata[0]);$i++) {
            $file = _MPDF_TEMP_PATH.'_tempCSSidata'.RAND(1,10000).'_'.$i.'.'.$idata[2][$i];
            //Save to local file
            file_put_contents($file, base64_decode($idata[3][$i]));
            // $this->mpdf->GetFullPath($file);    // ? is this needed - NO  mPDF 5.6.03
            $CSSstr = str_replace($idata[0][$i], 'url("'.$file.'")', $CSSstr);     // mPDF 5.5.17
        }
    }

    $CSSstr = preg_replace('/(<\!\-\-|\-\->)/s',' ',$CSSstr);

    // mPDF 5.7.4 URLs
    // Characters "(" ")" and ";" in url() e.g. background-image, cause problems parsing the CSS string
    // URLencode ( and ), but change ";" to a code which can be converted back after parsing (so as not to confuse ; 
    // with a segment delimiter in the URI)
    $tempmarker = '%ZZ';
    if (strpos($CSSstr,'url(')!==false) {
        preg_match_all( '/url\(\"(.*?)\"\)/', $CSSstr, $m);
        for($i = 0; $i < count($m[1]) ; $i++) {
            $tmp = str_replace(array('(',')',';'),array('%28','%29',$tempmarker),$m[1][$i]);
            $CSSstr = preg_replace('/'.preg_quote($m[0][$i],'/').'/', 'url(\''.$tmp.'\')', $CSSstr);
        }
        preg_match_all( '/url\(\'(.*?)\'\)/', $CSSstr, $m);
        for($i = 0; $i < count($m[1]) ; $i++) {
            $tmp = str_replace(array('(',')',';'),array('%28','%29',$tempmarker),$m[1][$i]);
            $CSSstr = preg_replace('/'.preg_quote($m[0][$i],'/').'/', 'url(\''.$tmp.'\')', $CSSstr);
        }
        preg_match_all( '/url\(([^\'\"].*?[^\'\"])\)/', $CSSstr, $m);
        for($i = 0; $i < count($m[1]) ; $i++) {
            $tmp = str_replace(array('(',')',';'),array('%28','%29',$tempmarker),$m[1][$i]);
            $CSSstr = preg_replace('/'.preg_quote($m[0][$i],'/').'/', 'url(\''.$tmp.'\')', $CSSstr);
        }
    }



    if ($CSSstr ) {
        $classproperties = array();    // mPDF 6
        preg_match_all('/(.*?)\{(.*?)\}/',$CSSstr,$styles);
        for($i=0; $i < count($styles[1]) ; $i++)  {
            // SET array e.g. $classproperties['COLOR'] = '#ffffff';
             $stylestr= trim($styles[2][$i]);
            $stylearr = explode(';',$stylestr);
            foreach($stylearr AS $sta) {
                if (trim($sta)) { 
                    // Changed to allow style="background: url('http://www.bpm1.com/bg.jpg')"
                    $tmp = explode(':',$sta,2);
                    $property = $tmp[0];
                    if (isset($tmp[1])) { $value = $tmp[1]; }
                    else { $value = ''; }
                    $value = str_replace($tempmarker,';',$value);    // mPDF 5.7.4 URLs
                    $property = trim($property);
                    $value = preg_replace('/\s*!important/i','',$value);
                    $value = trim($value);
                    if ($property && ($value || $value==='0')) {
                    // Ignores -webkit-gradient so doesn't override -moz-
                        if ((strtoupper($property)=='BACKGROUND-IMAGE' || strtoupper($property)=='BACKGROUND') && preg_match('/-webkit-gradient/i',$value)) { 
                            continue; 
                        }
                          $classproperties[strtoupper($property)] = $value;
                    }
                }
            }
            $classproperties = $this->fixCSS($classproperties);
            $tagstr = strtoupper(trim($styles[1][$i]));
            $tagarr = explode(',',$tagstr);
            $pageselectors = false;    // used to turn on $this->mpdf->mirrorMargins
            foreach($tagarr AS $tg) {
                // mPDF 5.7.4
                if (preg_match('/NTH-CHILD\((\s*(([\-+]?\d*)N(\s*[\-+]\s*\d+)?|[\-+]?\d+|ODD|EVEN)\s*)\)/',$tg,$m) ) {
                    $tg = preg_replace('/NTH-CHILD\(.*\)/', 'NTH-CHILD('.str_replace(' ','',$m[1]).')', $tg);
                }
                $tags = preg_split('/\s+/',trim($tg));
                $level = count($tags);
                $t = '';
                $t2 = '';
                $t3 = '';
                if (trim($tags[0])=='@PAGE') {
                    if (isset($tags[0])) { $t = trim($tags[0]); }
                    if (isset($tags[1])) { $t2 = trim($tags[1]); }
                    if (isset($tags[2])) { $t3 = trim($tags[2]); }
                    $tag = '';
                    if ($level==1) { $tag = $t; }
                    else if ($level==2 && preg_match('/^[:](.*)$/',$t2,$m)) { 
                        $tag = $t.'>>PSEUDO>>'.$m[1]; 
                        if ($m[1]=='LEFT' || $m[1]=='RIGHT') { $pageselectors = true; }    // used to turn on $this->mpdf->mirrorMargins 
                    }
                    else if ($level==2) { $tag = $t.'>>NAMED>>'.$t2; }
                    else if ($level==3 && preg_match('/^[:](.*)$/',$t3,$m)) { 
                        $tag = $t.'>>NAMED>>'.$t2.'>>PSEUDO>>'.$m[1]; 
                        if ($m[1]=='LEFT' || $m[1]=='RIGHT') { $pageselectors = true; }    // used to turn on $this->mpdf->mirrorMargins
                    }
                    if (isset($this->CSS[$tag]) && $tag) { $this->CSS[$tag] = $this->array_merge_recursive_unique($this->CSS[$tag], $classproperties); }
                    else if ($tag) { $this->CSS[$tag] = $classproperties; }
                }

                else if ($level == 1) {        // e.g. p or .class or #id or p.class or p#id
                if (isset($tags[0])) { $t = trim($tags[0]); }
                    if ($t) {
                        $tag = '';
                        if (preg_match('/^[.](.*)$/',$t,$m)) { $tag = 'CLASS>>'.$m[1]; }
                        else if (preg_match('/^[#](.*)$/',$t,$m)) { $tag = 'ID>>'.$m[1]; }
                        else if (preg_match('/^\[LANG=[\'\"]{0,1}([A-Z\-]{2,11})[\'\"]{0,1}\]$/',$t,$m)) { $tag = 'LANG>>'.strtolower($m[1]); }    // mPDF 6  Special case for lang as attribute selector
                        else if (preg_match('/^:LANG\([\'\"]{0,1}([A-Z\-]{2,11})[\'\"]{0,1}\)$/',$t,$m)) { $tag = 'LANG>>'.strtolower($m[1]); }    // mPDF 6  Special case for lang as attribute selector
                        else if (preg_match('/^('.$this->mpdf->allowedCSStags.')[.](.*)$/',$t,$m)) { $tag = $m[1].'>>CLASS>>'.$m[2]; }
                        else if (preg_match('/^('.$this->mpdf->allowedCSStags.')\s*:NTH-CHILD\((.*)\)$/',$t,$m)) { $tag = $m[1].'>>SELECTORNTHCHILD>>'.$m[2]; }
                        else if (preg_match('/^('.$this->mpdf->allowedCSStags.')[#](.*)$/',$t,$m)) { $tag = $m[1].'>>ID>>'.$m[2]; }
                        else if (preg_match('/^('.$this->mpdf->allowedCSStags.')\[LANG=[\'\"]{0,1}([A-Z\-]{2,11})[\'\"]{0,1}\]$/',$t,$m)) { $tag = $m[1].'>>LANG>>'.strtolower($m[2]); }    // mPDF 6  Special case for lang as attribute selector
                        else if (preg_match('/^('.$this->mpdf->allowedCSStags.'):LANG\([\'\"]{0,1}([A-Z\-]{2,11})[\'\"]{0,1}\)$/',$t,$m)) { $tag = $m[1].'>>LANG>>'.strtolower($m[2]); }    // mPDF 6  Special case for lang as attribute selector
                        else if (preg_match('/^('.$this->mpdf->allowedCSStags.')$/',$t)) { $tag= $t; }
                        if (isset($this->CSS[$tag]) && $tag) { $this->CSS[$tag] = $this->array_merge_recursive_unique($this->CSS[$tag], $classproperties); }
                        else if ($tag) { $this->CSS[$tag] = $classproperties; }
                    }
                }
                else {
                    $tmp = array();
                    for($n=0;$n<$level;$n++) {
                        if (isset($tags[$n])) { $t = trim($tags[$n]); }
                        else { $t = ''; }
                        if ($t) {
                            $tag = '';
                            if (preg_match('/^[.](.*)$/',$t,$m)) { $tag = 'CLASS>>'.$m[1]; }
                            else if (preg_match('/^[#](.*)$/',$t,$m)) { $tag = 'ID>>'.$m[1]; }
                            else if (preg_match('/^\[LANG=[\'\"]{0,1}([A-Z\-]{2,11})[\'\"]{0,1}\]$/',$t,$m)) { $tag = 'LANG>>'.strtolower($m[1]); }    // mPDF 6  Special case for lang as attribute selector
                            else if (preg_match('/^:LANG\([\'\"]{0,1}([A-Z\-]{2,11})[\'\"]{0,1}\)$/',$t,$m)) { $tag = 'LANG>>'.strtolower($m[1]); }    // mPDF 6  Special case for lang as attribute selector
                            else if (preg_match('/^('.$this->mpdf->allowedCSStags.')[.](.*)$/',$t,$m)) { $tag = $m[1].'>>CLASS>>'.$m[2]; }
                            else if (preg_match('/^('.$this->mpdf->allowedCSStags.')\s*:NTH-CHILD\((.*)\)$/',$t,$m)) { $tag = $m[1].'>>SELECTORNTHCHILD>>'.$m[2]; }
                            else if (preg_match('/^('.$this->mpdf->allowedCSStags.')[#](.*)$/',$t,$m)) { $tag = $m[1].'>>ID>>'.$m[2]; }
                            else if (preg_match('/^('.$this->mpdf->allowedCSStags.')\[LANG=[\'\"]{0,1}([A-Z\-]{2,11})[\'\"]{0,1}\]$/',$t,$m)) { $tag = $m[1].'>>LANG>>'.strtolower($m[2]); }    // mPDF 6  Special case for lang as attribute selector
                            else if (preg_match('/^('.$this->mpdf->allowedCSStags.'):LANG\([\'\"]{0,1}([A-Z\-]{2,11})[\'\"]{0,1}\)$/',$t,$m)) { $tag = $m[1].'>>LANG>>'.strtolower($m[2]); }    // mPDF 6  Special case for lang as attribute selector
                            else if (preg_match('/^('.$this->mpdf->allowedCSStags.')$/',$t)) { $tag= $t; }

                            if ($tag) $tmp[] = $tag;
                            else { break; }
                        }
                    }
           
                    if ($tag) {
                        $x = &$this->cascadeCSS; 
                        foreach($tmp AS $tp) { $x = &$x[$tp]; }
                        $x = $this->array_merge_recursive_unique($x, $classproperties); 
                        $x['depth'] = $level;
                    }
                }
            }
            if ($pageselectors) { $this->mpdf->mirrorMargins = true; }
              $properties = array();
              $values = array();
              $classproperties = array();
        }
    } // end of if
    //Remove CSS (tags and content), if any
    $regexp = '/<style.*?>(.*?)<\/style>/si'; // it can be <style> or <style type="txt/css"> 
    $html = preg_replace($regexp,'',$html);
//print_r($this->CSS); exit;
//print_r($this->cascadeCSS); exit;
    return $html;
}
