在php中改变动画gif中的颜色

时间:2013-03-18 14:31:36

标签: php animated-gif

是否有任何工作示例如何读取动画gif,使用GD库或ImageMagick更改其任何帧中任何像素的颜色并再次将其另存为动画gif?

我已经谷歌搜索了2天,我没有在任何地方找到答案。

编辑: 我有几乎完美的解决方案。但是一些透明(动画)的GIF不能正确保持透明度(只有部分透明度被破坏)。

来源:

  • 其中一张错误的图片:http://commons.wikimedia.org/wiki/File:Animation30.gif
  • GifFrameExtractor类:https://github.com/Sybio/GifFrameExtractor
  • GIFEncoder类:http://www.phpclasses.org/package/3163-PHP-Generate-GIF-animations-from-a-set-of-GIF-images.html

    require_once('GIFEncoder.class.php');
    require_once('GifFrameExtractor-master/src/GifFrameExtractor/GifFrameExtractor.php');
    
    $gifFilePath = "input.gif";
    // check this is an animated GIF
    if (!\GifFrameExtractor\GifFrameExtractor::isAnimatedGif($gifFilePath)) {
        \die('not an namiated image');
    }
    
    $gfe = new \GifFrameExtractor\GifFrameExtractor();
    $gfe->extract($gifFilePath);
    // frames as a GD source
    $frameImages = $gfe->getFrameImages();
    $frameDurations = $gfe->getFrameDurations();
    // color used as a transparent color, if any
    $tColor = array('red' => -1,'green'=>-1,'blue'=>-1);
    
    foreach($frameImages as $i => $gdSource) {
        // do something with gdSource
        colorize($gdSource);
        if($i == 0) {
            //get the color used as transparent
            // should be for any frame the same
            $tColor = getTransparentColor($gdSource);
        }
        //GIFEncoder works only with binary data or files
        //It cant work with gd source
        //Therfore i output the gd source to stdout, catch it
        //and use it as binary data.
        //It could be memory consuming, so you might write the
        //frames as a file and then use them instead of binary data.
        \ob_start();          // catch output
        \imagegif($gdSource); // write binary data to output
        $frameImages[$i] =  \ob_get_contents(); //replace GD source by the binary data
        \ob_end_clean();
    }
    
    
    // create animated gif
    $gif = new \GIFEncoder(
            $frameImages, //binary data (or path to images on file system)
            $frameDurations,
            0, // infinite loop
            2, // dont know what is this for (number 0-3 or -1 to ignore)
            $tColor['red'], $tColor['green'], $tColor['blue'],
            'bin' // or 'url' if $frameImages is array of paths to images on file system
    );
    // write image to file system
    \FWrite ( \FOpen ( "output.gif", "wb" ), $gif->GetAnimation ( ) );
    // send image to browser
    //Header ( 'Content-type:image/gif' );
    //echo  $gif->GetAnimation ( );
    

//有用的功能

    /**
     * Make grayscale color
     * @param $color array('red'=>,'green'=>,'blue'=>);
     * @return array('red'=>,'green'=>,'blue'=>);
     */
    function transformColor($color) {
        $gst = $color['red']*0.15+$color['green']*0.5+$color['blue']*0.35;
        $color['red'] = $color['green'] = $color['blue'] = $gst;
         return $color;
    }  

//有用的功能

    /**
     * Get the transparent color from GD resource.
     * If no tranpsarent color, all returned RGB values are -1
     * @param $rs GD resource
     * @return array('red'=>,'green'=>,'blue'=>)
     */
    function getTransparentColor($rs) {
        $transparentIndex = \ImageColorTransparent($rs);
        $transparentColor = NULL;

        if ($transparentIndex >= 0 && $transparentIndex < \ImageColorsTotal($rs)) {
            $transparentColor = @\ImageColorsForIndex($rs, $transparentIndex);
        }
        return $transparentColor ? $transparentColor : array('red' => -1,'green'=>-1,'blue'=>-1);
    }

//使用透明度转换GD资源 //可能存在问题,因为如果单独保存帧,则会出现上述透明度问题

    function colorize($rs) {
        assert('gd' === \get_resource_type($rs));
            // you might want to create copy of the source here 
            // (instead of resource alias)
            $bild = $rs;

            //width
            $x = \imagesx($bild);
            // height
            $y = \imagesy($bild);

            $transparentIndex = \ImageColorTransparent($rs);
            $transparentColor = NULL;

            if ($transparentIndex >= 0 && $transparentIndex < \ImageColorsTotal($bild)) {

                $transparentColor = @\ImageColorsForIndex($rs, $transparentIndex);
            }

            \ImageSaveAlpha($bild, TRUE);
            \ImageAlphaBlending($bild, FALSE);

            $transparentNewIndex = NULL;
            $transparentNewColor = NULL;

            if (!empty($transparentColor)) {
                $transparentIndexNew = \ImageColorAllocate($bild, 255, 0, 255);
                \ImageColorTransparent($bild, $transparentIndexNew);
                $transparentColorNew = @ImageColorsForIndex($bild, transparentIndexNew);
            }
             // transform pixels
            for ($i = 0; $i < $y; $i++) {
                for ($j = 0; $j < $x; $j++) {
                    $index = \imagecolorat($rs, $j, $i);
                    $color = \imagecolorsforindex($rs, $index);
                    if ($index === $transparentIndex) {
                        $col = $transparentIndexNew;
                    } else {
                        $rgb = transformColor($color);
                        //TODO: we have a problem here, if $rgb ~= $transparentColorNew,
                        //      then this pixel will be transparent and not the desired  color
                        $col = \imagecolorresolvealpha($bild, $rgb['red'], $rgb['green'], $rgb['blue'], intval($color['alpha']));
                        if($col == $transparentIndexNew) {
                            //TODO: fix the color not to be transparent
                            // it do not die with the example gif 
                            //die('This might be a problem, but not the problem describlet above this example');
                        }
                    }
                    \imagesetpixel($bild, $j, $i, $col);
                }
            }

            return $bild;
        }

2 个答案:

答案 0 :(得分:1)

我认为动画GIF有多个帧,因此算法是将gif作为多个帧读取,更改每个帧中的像素颜色,然后再次保存。你能在GD中加载动画gif吗?

也许这个库可以帮助您回写GIF图像:http://www.phpclasses.org/package/3163-PHP-Generate-GIF-animations-from-a-set-of-GIF-images.html

答案 1 :(得分:1)

$file = "yourImage.gif";
$im = imagecreatefromgif ($file);

$index = imagecolorclosest ( $im,  255,255,255 ); // get your color (rgb)
imagecolorset($im,$index,92,92,92); // set new color (rgb)

$file= "yourResult.gif";
imagegif($im, $file); // save image as gif
imagedestroy($im);

我不确定这是否适用于GIF动画。