Решаем проблему с полупрозрачностью PNG в Internet Explorer

Как известно, Internet Explorer младше 7-й версии не умеет отображать альфа-канал в файлах PNG. Существует несколько вариантов решений проблемы на клиентском коде, но на Symfony есть возможность соорудить серверную логику и подключать ее в каждом проекте.

На есть http://www.symfony-project.org/ готовый снипет, его и используем.

для начала вот такой код:

class pngAlphaFilter extends sfFilter
{
  public function execute ($filterChain)
  {
    $filterChain->execute();
  }

  public function executeBeforeRendering ($filterChain)
  {
    $response = $this->getContext()->getResponse();

    $content = $response->getContent();
    $newContent = $this->replacePngTags($content, '/images/');
    $response->setContent($newContent);

    $filterChain->execute();
  }

  /**
  *  KOIVI PNG Alpha IMG Tag Replacer for PHP (C) 2004 Justin Koivisto
  *  Version 2.0.12
  *  Last Modified: 12/30/2005
  *
  *  Modifies IMG and INPUT tags for MSIE5+ browsers to ensure that PNG-24
  *  transparencies are displayed correctly.  Replaces original SRC attribute
  *  with a binary transparent PNG file (spacer.png) that is located in the same
  *  directory as the orignal image, and adds the STYLE attribute needed to for
  *  the browser. (Matching is case-insensitive. However, the width attribute
  *  should come before height.
  *
  *  Also replaces code for PNG images specified as backgrounds via:
  *  background-image: url(image.png); or background-image: url('image.png');
  *  When using PNG images in the background, there is no need to use a spacer.png
  *  image. (Only supports inline CSS at this point.)
  *
  *  @param string $x  String containing the content to search and replace in.
  *  @param string $img_path   The path to the directory with the spacer image relative to
  *                      the DOCUMENT_ROOT. If none os supplied, the spacer.png image
  *                      should be in the same directory as PNG-24 image.
  *  @param string $sizeMeth   String containing the sizingMethod to be used in the
  *                      Microsoft.AlphaImageLoader call. Possible values are:
  *                      crop - Clips the image to fit the dimensions of the object.
  *                      image - Enlarges or reduces the border of the object to fit
  *                              the dimensions of the image.
  *                      scale - Default. Stretches or shrinks the image to fill the borders
  *                              of the object.
  *  @param bool   $inScript  Boolean flag indicating whether or not to replace IMG tags that
  *                      appear within SCRIPT tags in the passed content. If used, may cause
  *                      javascript parse errors when the IMG tags is defined in a javascript
  *                      string. (Which is why the options was added.)
  *  @return string
  */
  public function replacePngTags($x,$img_path='',$sizeMeth='scale',$inScript=FALSE){
      $arr2=array();
      // make sure that we are only replacing for the Windows versions of Internet
      // Explorer 5.5+
      $msie='/msie\s(5\.[5-9]|[6]\.[0-9]*).*(win)/i';
      if( !isset($_SERVER['HTTP_USER_AGENT']) ||
          !preg_match($msie,$_SERVER['HTTP_USER_AGENT']) ||
          preg_match('/opera/i',$_SERVER['HTTP_USER_AGENT']))
          return $x;

      if($inScript){
          // first, I want to remove all scripts from the page…
          $saved_scripts=array();
          $placeholders=array();
          preg_match_all('<script[^>]*>(.*)</script>isU',$x,$scripts);
          for($i=0;$i<count($scripts[0]);$i++){
              $x=str_replace($scripts[0][$i],'replacePngTags_ScriptTag-'.$i,$x);
              $saved_scripts[]=$scripts[0][$i];
              $placeholders[]='replacePngTags_ScriptTag-'.$i;
          }
      }

      // find all the png images in backgrounds
      preg_match_all('/background-image:\s*url\(([\\"\\\']?)([^\)]+\.png)\1\);/Uis',$x,$background);
      for($i=0;$i<count($background[0]);$i++){
          // simply replace:
          //  "background-image: url('image.png');"
          // with:
          //  "filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(
          //      enabled=true, sizingMethod=scale, src='image.png');"
          // I don't think that the background-repeat styles will work with this…
          $x=str_replace($background[0][$i],'filter:progid:DXImageTransform.'.
                  'Microsoft.AlphaImageLoader(enabled=true, sizingMethod='.$sizeMeth.
                  ', src=\''.$background[2][$i].'\');',$x);
      }

      // find all the IMG tags with ".png" in them
      $pattern='/<(input|img)[^>]*src=([\\"\\\']?)([^>]*\.png)\2[^>]*>/i';
      preg_match_all($pattern,$x,$images);
      for($num_images=0;$num_images<count($images[0]);$num_images++){
          // for each found image pattern
          $original=$images[0][$num_images];
          $quote=$images[2][$num_images];
          $atts=''; $width=0; $height=0; $modified=$original;

          // We do this so that we can put our spacer.png image in the same
          // directory as the image - if a path wasn't passed to the function
          if(empty($img_path)){
              $tmp=split('[\\/]',$images[3][$num_images]);
              $this_img=array_pop($tmp);
              $img_path=join('/',$tmp);
              if(empty($img_path)){
                  // this was a relative URI, image should be in this directory
                  $tmp=split('[\\/]',$_SERVER['SCRIPT_NAME']);
                  array_pop($tmp);    // trash the script name, we only want the directory name
                  $img_path=join('/',$tmp).'/';
              }else{
                  $img_path.='/';
              }
          }else if(substr($img_path,-1)!='/'){
              // in case the supplied path didn't end with a /
              $img_path.='/';
          }

          // If the size is defined by styles, find them
          preg_match_all(
              '/style=([\\"\\\']).*(\s?width:\s?([0-9]+(px|%));).*'.
              '(\s?height:\s?([0-9]+(px|%));).*\\1/Ui',
                 $images[0][$num_images],$arr2);
          if(is_array($arr2) &amp;&amp; count($arr2[0])){
              // size was defined by styles, get values
              $width=$arr2[3][0];
              $height=$arr2[6][0];

              // remove the width and height from the style
              $stripper=str_replace(' ','\s','/('.$arr2[2][0].'|'.$arr2[5][0].')/');
              // Also remove any empty style tags
              $modified=preg_replace(
                  '`style='.$arr2[1][0].$arr2[1][0].'`i',
                  '',
                  preg_replace($stripper,'',$modified));
          }else{
              // size was not defined by styles, get values from attributes
              preg_match_all('/width=([\\"\\\']?)([0-9%]+)\\1/i',$images[0][$num_images],$arr2);
              if(is_array($arr2) &amp;&amp; count($arr2[0])){
                  $width=$arr2[2][0];
                  if(is_numeric($width))
                      $width.='px';

                  // remove width from the tag
                  $modified=str_replace($arr2[0][0],'',$modified);
              }
              preg_match_all('/height=([\\"\\\']?)([0-9%]+)\\1/i',$images[0][$num_images],$arr2);
              if(is_array($arr2) &amp;&amp; count($arr2[0])){
                  $height=$arr2[2][0];
                  if(is_numeric($height))
                      $height.='px';

                  // remove height from the tag
                  $modified=str_replace($arr2[0][0],'',$modified);
              }
          }

          if($width==0 || $height==0){
              // width and height not defined in HTML attributes or css style, try to get
              // them from the image itself
              // this does not work in all conditions… It is best to define width and
              // height in your img tag or with inline styles..
              if(file_exists($_SERVER['DOCUMENT_ROOT'].$img_path.$images[3][$num_images])){
                  // image is on this filesystem, get width &amp; height
                  $size=getimagesize($_SERVER['DOCUMENT_ROOT'].$img_path.$images[3][$num_images]);
                  $width=$size[0].'px';
                  $height=$size[1].'px';
              }else if(file_exists($_SERVER['DOCUMENT_ROOT'].$images[3][$num_images])){
                  // image is on this filesystem, get width &amp; height
                  $size=getimagesize($_SERVER['DOCUMENT_ROOT'].$images[3][$num_images]);
                  $width=$size[0].'px';
                  $height=$size[1].'px';
              }
          }

          // end quote is already supplied by originial src attribute
          $replace_src_with=$quote.$img_path.'spacer.png'.$quote.' style="width: '.$width.
              '; height: '.$height.'; filter: progid:DXImageTransform.'.
              'Microsoft.AlphaImageLoader(src=\''.$images[3][$num_images].'\', sizingMethod='.
              $sizeMeth.');"';

          // now create the new tag from the old
          $new_tag=str_replace($quote.$images[3][$num_images].$quote,$replace_src_with,
              str_replace('  ',' ',$modified));
          // now place the new tag into the content
          $x=str_replace($original,$new_tag,$x);
      }

      if($inScript){
          // before the return, put the script tags back in. (I was having problems when there was
          // javascript that had image tags for PNGs in it when using this function…
          $x=str_replace($placeholders,$saved_scripts,$x);
      }

      return $x;
  }
}

Этот код пишем в файл pngAlphaFilter.class.php и кладем его в директорию lib нашего приложения.

Далее активируем фильтр в файле filters.yml

pngAlphaFilter:
class: pngAlphaFilter

Далее кладем прозрачный PNG spacer.png в директорию с изображениями (web/images). Файл можно взять здесь http://koivi.com/ie-png-transparency/spacer.png

Теперь полупрозрачность в нашем приложении будет работать. Никаких изменений в шаблонах или CSS делать не нужно

Теги: , , ,

Вы можете оставить комментарий или подписаться на RSS feed

Коментарии

Бесполезный изврат

[...] http://symfony.org.ua/2008/07/poluprozrachnost-png-internet-explorer/ - способ заставить работать альфа-прозрачность в IE 6. [...]

Офигенная статья, тот кто не шарит в php и png, тот не поймет всей важности данного материала.

Оставить комментарий

(обязательно)

(обязательно)