Animating gifs with GD

PHP programming forum. Ask questions or help people concerning PHP code. Don't understand a function? Need help implementing a class? Don't understand a class? Here is where to ask. Remember to do your homework!

Moderator: General Moderators

Post Reply
helraizer
Forum Commoner
Posts: 31
Joined: Thu Jun 05, 2008 8:20 pm

Animating gifs with GD

Post by helraizer »

Hey folks,

I'm working on animating gifs in GD. I've adapted the use of the GIFEncoder class from phpclasses.
original
gif.php

Code: Select all

 
<?php
 
 
Class GIFAnimator {
    var $GIF = "GIF89a";       
    var $VER = "GIFEncoder V2.05";    
 
    var $BUF = Array ( );
    var $LOP =  0;
    var $DIS =  2;
    var $COL = -1;
    var $IMG = -1;
 
    var $ERR = Array (
        ERR00=>"Does not supported function for only one image!",
        ERR01=>"Source is not a GIF image!",
        ERR02=>"Unintelligible flag ",
        ERR03=>"Does not make animation from animated GIF source",
    );
 
   
    function GIFAnimator    (
                            $GIF_src, $GIF_dly, $GIF_lop, $GIF_dis,
                            $GIF_red, $GIF_grn, $GIF_blu, $GIF_mod
                        ) {
        if ( ! is_array ( $GIF_src ) && ! is_array ( $GIF_tim ) ) {
            printf    ( "%s: %s", $this->VER, $this->ERR [ 'ERR00' ] );
            exit    ( 0 );
        }
        $this->LOP = ( $GIF_lop > -1 ) ? $GIF_lop : 0;
        $this->DIS = ( $GIF_dis > -1 ) ? ( ( $GIF_dis < 3 ) ? $GIF_dis : 3 ) : 2;
        $this->COL = ( $GIF_red > -1 && $GIF_grn > -1 && $GIF_blu > -1 ) ?
                        ( $GIF_red | ( $GIF_grn << 8 ) | ( $GIF_blu << 16 ) ) : -1;
 
        for ( $i = 0; $i < count ( $GIF_src ); $i++ ) {
            if ( strToLower ( $GIF_mod ) == "url" ) {
                $this->BUF [ ] = fread ( fopen ( $GIF_src [ $i ], "rb" ), filesize ( $GIF_src [ $i ] ) );
            }
            else if ( strToLower ( $GIF_mod ) == "bin" ) {
                $this->BUF [ ] = $GIF_src [ $i ];
            }
            else {
                printf    ( "%s: %s ( %s )!", $this->VER, $this->ERR [ 'ERR02' ], $GIF_mod );
                exit    ( 0 );
            }
            if ( substr ( $this->BUF [ $i ], 0, 6 ) != "GIF87a" && substr ( $this->BUF [ $i ], 0, 6 ) != "GIF89a" ) {
                printf    ( "%s: %d %s", $this->VER, $i, $this->ERR [ 'ERR01' ] );
                exit    ( 0 );
            }
            for ( $j = ( 13 + 3 * ( 2 << ( ord ( $this->BUF [ $i ] { 10 } ) & 0x07 ) ) ), $k = TRUE; $k; $j++ ) {
                switch ( $this->BUF [ $i ] { $j } ) {
                    case "!":
                        if ( ( substr ( $this->BUF [ $i ], ( $j + 3 ), 8 ) ) == "NETSCAPE" ) {
                            printf    ( "%s: %s ( %s source )!", $this->VER, $this->ERR [ 'ERR03' ], ( $i + 1 ) );
                            exit    ( 0 );
                        }
                        break;
                    case ";":
                        $k = FALSE;
                        break;
                }
            }
        }
        GIFAnimator::GIFHead ( );
        for ( $i = 0; $i < count ( $this->BUF ); $i++ ) {
            GIFAnimator::GIFGetFrames ( $i, $GIF_dly [ $i ] );
        }
        GIFAnimator::GIFFoot ( );
    }
   
    function GIFHead ( ) {
        $cmap = 0;
 
        if ( ord ( $this->BUF [ 0 ] { 10 } ) & 0x80 ) {
            $cmap = 3 * ( 2 << ( ord ( $this->BUF [ 0 ] { 10 } ) & 0x07 ) );
 
            $this->GIF .= substr ( $this->BUF [ 0 ], 6, 7        );
            $this->GIF .= substr ( $this->BUF [ 0 ], 13, $cmap    );
            $this->GIF .= "!\377\13NETSCAPE2.0\3\1" . GIFAnimator::GIFWord ( $this->LOP ) . "\0";
        }
    }
  
    function GIFGetFrames ( $i, $d ) {
 
        $Locals_str = 13 + 3 * ( 2 << ( ord ( $this->BUF [ $i ] { 10 } ) & 0x07 ) );
 
        $Locals_end = strlen ( $this->BUF [ $i ] ) - $Locals_str - 1;
        $Locals_tmp = substr ( $this->BUF [ $i ], $Locals_str, $Locals_end );
 
        $Global_len = 2 << ( ord ( $this->BUF [ 0  ] { 10 } ) & 0x07 );
        $Locals_len = 2 << ( ord ( $this->BUF [ $i ] { 10 } ) & 0x07 );
 
        $Global_rgb = substr ( $this->BUF [ 0  ], 13,
                            3 * ( 2 << ( ord ( $this->BUF [ 0  ] { 10 } ) & 0x07 ) ) );
        $Locals_rgb = substr ( $this->BUF [ $i ], 13,
                            3 * ( 2 << ( ord ( $this->BUF [ $i ] { 10 } ) & 0x07 ) ) );
 
        $Locals_ext = "!\xF9\x04" . chr ( ( $this->DIS << 2 ) + 0 ) .
                        chr ( ( $d >> 0 ) & 0xFF ) . chr ( ( $d >> 8 ) & 0xFF ) . "\x0\x0";
 
        if ( $this->COL > -1 && ord ( $this->BUF [ $i ] { 10 } ) & 0x80 ) {
            for ( $j = 0; $j < ( 2 << ( ord ( $this->BUF [ $i ] { 10 } ) & 0x07 ) ); $j++ ) {
                if    (
                        ord ( $Locals_rgb { 3 * $j + 0 } ) == ( ( $this->COL >> 16 ) & 0xFF ) &&
                        ord ( $Locals_rgb { 3 * $j + 1 } ) == ( ( $this->COL >>  8 ) & 0xFF ) &&
                        ord ( $Locals_rgb { 3 * $j + 2 } ) == ( ( $this->COL >>  0 ) & 0xFF )
                    ) {
                    $Locals_ext = "!\xF9\x04" . chr ( ( $this->DIS << 2 ) + 1 ) .
                                    chr ( ( $d >> 0 ) & 0xFF ) . chr ( ( $d >> 8 ) & 0xFF ) . chr ( $j ) . "\x0";
                    break;
                }
            }
        }
        switch ( $Locals_tmp { 0 } ) {
            case "!":
                $Locals_img = substr ( $Locals_tmp, 8, 10 );
                $Locals_tmp = substr ( $Locals_tmp, 18, strlen ( $Locals_tmp ) - 18 );
                break;
            case ",":
                $Locals_img = substr ( $Locals_tmp, 0, 10 );
                $Locals_tmp = substr ( $Locals_tmp, 10, strlen ( $Locals_tmp ) - 10 );
                break;
        }
        if ( ord ( $this->BUF [ $i ] { 10 } ) & 0x80 && $this->IMG > -1 ) {
            if ( $Global_len == $Locals_len ) {
                if ( GIFAnimator::GIFBlock ( $Global_rgb, $Locals_rgb, $Global_len ) ) {
                    $this->GIF .= ( $Locals_ext . $Locals_img . $Locals_tmp );
                }
                else {
                    $byte  = ord ( $Locals_img { 9 } );
                    $byte |= 0x80;
                    $byte &= 0xF8;
                    $byte |= ( ord ( $this->BUF [ 0 ] { 10 } ) & 0x07 );
                    $Locals_img { 9 } = chr ( $byte );
                    $this->GIF .= ( $Locals_ext . $Locals_img . $Locals_rgb . $Locals_tmp );
                }
            }
            else {
                $byte  = ord ( $Locals_img { 9 } );
                $byte |= 0x80;
                $byte &= 0xF8;
                $byte |= ( ord ( $this->BUF [ $i ] { 10 } ) & 0x07 );
                $Locals_img { 9 } = chr ( $byte );
                $this->GIF .= ( $Locals_ext . $Locals_img . $Locals_rgb . $Locals_tmp );
            }
        }
        else {
            $this->GIF .= ( $Locals_ext . $Locals_img . $Locals_tmp );
        }
        $this->IMG  = 1;
    }
    
    function GIFFoot ( ) {
        $this->GIF .= ";";
    }
   
    function GIFBlock ( $GlobalBlock, $LocalBlock, $Len ) {
 
        for ( $i = 0; $i < $Len; $i++ ) {
            if    (
                    $GlobalBlock { 3 * $i + 0 } != $LocalBlock { 3 * $i + 0 } ||
                    $GlobalBlock { 3 * $i + 1 } != $LocalBlock { 3 * $i + 1 } ||
                    $GlobalBlock { 3 * $i + 2 } != $LocalBlock { 3 * $i + 2 }
                ) {
                    return ( 0 );
            }
        }
 
        return ( 1 );
    }
   
    function GIFWord ( $int ) {
 
        return ( chr ( $int & 0xFF ) . chr ( ( $int >> 8 ) & 0xFF ) );
    }
    
    function GetAnimation ( ) {
        return ( $this->GIF );
    }
} 
 
?>
 


I have used

Code: Select all

<?php
 
include('gif.php');
 
$image = imagecreatefrompng("../mychatbox/user/helraizer1.png");
 
 
if ( $dh = opendir ( "frames/" ) ) {
 
    while ( false !== ( $dat = readdir ( $dh ) ) ) {
 
        if ( $dat != "." && $dat != ".." ) {
 
            $frames [ ] .= "frames/$dat";
 
            $framed [ ] = 20;
 
        }
 
    }
 
    closedir ( $dh );
 
}
   
    foreach( $frames as $thePfhrame )
   
      {
   
          $imgPfhrame = imagecreatefromgif($thePfhrame);
   
          imagecopymerge($image, $imgPfhrame, imageSX($image)/2, imageSY($image)/1.5, 0, 0, 15, 15, 100);
   
          
          
        
      }
      
 
  $gif = new GIFAnimator    (
 
                            $frames, //sources - URL or path
 
                            $framed, //delay times - int
 
                            0, //Animation loops - int - 0 is infinite
 
                            2, //Disposal - int
 
                            -1, -1, -1, //transparency red, green, blue - int
 
                            "url" // source type
 
        );
   
   
    
 
       
 
        header("Content-Type: image/gif");
 
echo $gif->GetAnimation();
 
 
FWrite ( FOpen ( "img.gif", "wb" ), $gif->GetAnimation ( ) );
 
 
?>  


and it produces this:

Image

As you can see the one that is in middle is animated! So that works perfectly fine, on its own.

However when I put the code in my showimage script (to produce the shoutbox), which is in a different folder, but still has a 'frames' folder with the same frames in it, it gives me the error.
GIFEncoder V2.05: Does not supported function for only one image!
Even though there are 9 frames in the folder.

Code: Select all

 
if(stristr($line, ":roll:")) {
            session_register("roll");
            $_SESSION['roll'] = 1;
        }
       
if (isset($filter)) {
header("Content-Type: image/png"); // tell the browser what we're gonna give it
    imagepng($image);
 
} elseif ($page == 1) {
 
if(!isset($_SESSION['roll'])) {
    header("Content-Type: image/png"); // tell the browser what we're gonna give it
    imagepng($image);
 imagepng($image, "./user/" . $user . $box. ".png");
 
} else {
    
     $pos = strpos($line, ":roll:");
 
        if ($font == "palab") {
            $post = $pos * 5.7;
        } elseif ($font == "comicsans") {
            $post = $pos * 6.725;
        } elseif ($font == "calibri") {
            $post = $pos * 5;
        } elseif ($font == "courbd") {
            $post = ($pos * 5.<!-- s8) --><img src=\"{SMILIES_PATH}/icon_cool.gif\" alt=\"8)\" title=\"Cool\" /><!-- s8) --> + 1;
        } elseif ($font == "arial") {
            $post = ($pos * 7.3) + 1;
        } else {
 
        }
    
 
            
      if ( $dh = opendir ( "frames/" ) ) {
 
    while ( false !== ( $dat = readdir ( $dh ) ) ) {
 
        if ( $dat != "." && $dat != ".." ) {
 
            $frames [ ] .= "frames/$dat";
 
            $framed [ ] = 17;
 
        }
 
    }
 
    closedir ( $dh );
 
}
   
    foreach( $frames as $thePfhrame )
   
      {
   
          $imgPfhrame = imagecreatefromgif($thePfhrame);
   
          imagecopymerge($image, $imgPfhrame, ($cur_line_x + $post) + 6, (($cur_line_y + $lineheight) - 30.5), 0, 0, 15, 15, 100);
   
          
          
        
      }
      
 
  $gif = new GIFAnimator    (
 
                            $frames, //sources - URL or path
 
                            $framed, //delay times - int
 
                            0, //Animation loops - int - 0 is infinite
 
                            2, //Disposal - int
 
                            -1, -1, -1, //transparency red, green, blue - int
 
                            "url" // source type
 
        );
   
   
    
 
       
 
        header("Content-Type: image/gif");
 
echo $gif->GetAnimation();
 
 
FWrite ( FOpen ( "helraizer2.gif", "wb" ), $gif->GetAnimation ( ) );
 
}
 
 
else {
    header("Content-Type: image/png"); // tell the browser what we're gonna give it
    imagepng($image);
 
}
 
 
The error comes about if $frames isn't an array but, it is. Any idea why this happens?

Sam
helraizer
Forum Commoner
Posts: 31
Joined: Thu Jun 05, 2008 8:20 pm

Re: Animating gifs with GD

Post by helraizer »

There was a misnamed variable in gif.php; that's stopped the first error.

However now an odd result has turned out. The script on its own gives the picture I linked to in my previous post.

However in the code when it's within the showimage script if the characters ':roll:' is found in any of the lines of text on the image it overrides the entire shoutbox image as the animated gif. Just the smiley, not the image with the emoticon on it.

Here is the relevant code, can you see any problems?

Code: Select all

 
 $image = imagecreatefromgif("./user/" . $user . "_back.gif");
 
 $im = ImageCreate($wid, 35);
        $black_a = imagecolorallocate($im, 0, 0, 0);
        $white_a = imagecolortransparent($im, $black_a);
        $white = ImageColorAllocate($im, 255, 255, 255);
        ImageFill($im, 0, 0, $white_a);
        Imagettftext($im, 15, 0, 10, 30, $white, $font, $top);
 
 $cur_line_y = 59;
 
 
 $imgs = imagecreatetruecolor($wid, 35);
        $blark = imagecolorallocate($imgs, 0, 0, 0);
        $whitre = imagecolortransparent($imgs, $blark);
        $whiter = imagecolorallocate($imgs, 255, 255, 255);
        ImageFill($imgs, 0, 0, $whitre);
        imagettftext($imgs, 10, 2, 10, 30, $whiter, $fontstick, "JustShout!");
 
 
$sql = "SELECT * FROM user INNER JOIN tblcomments ON tblcomments.user_id=user.user_id INNER JOIN tblattributes ON tblcomments.id = tblattributes.id INNER JOIN tblip ON tblattributes.id = tblip.id  WHERE tblcomments.user_id='$user_id' AND tblattributes.user_id='$user_id' AND tblip.user_id='$user_id' AND tblcomments.box_id=$box AND tblattributes.box_id=$box AND tblip.box_id=$box ORDER BY tblcomments.`id` DESC $max";
 
$result = mysql_query($sql) or die("error in  sqllls: " . mysql_error());
 
 
$cur_line_x = 24; // This stores how far across the image the current line will print
$pagecharwidth = 75; // this is the maximum length of the line before it wraps;
$lineheight = 18; // This is how much to move down to print the next line
$pagelinelimit = 1; // This is the maximum number lines of text that can be displayed
 
 
for ($i = 0; $i < $numberOfLines; $i++) {
    while ($row = mysql_fetch_array($result)) {
 
        $count = mysql_num_rows($result);
 
        $name = "[" . htmlspecialchars_decode($row['username']) . "] "; //it works - returns username
        $font = trim($row['font']); //it works - renders the colour
        $color = trim($row['color']); //it works - changes the font
        $oldline = htmlspecialchars_decode($row['comment']); //it works, posts the shout
        $array = array("\r\n", "\n", "\r");
        $replace = " ";
        $line = str_replace($array, $replace, $oldline);
 
 
if ($back == "m" || $col == "a") {
 
            $whit = imagecolorallocate($image, 255, 255, 255);
 
            if ($color == "white" || $color == "yellow" || $color == "green" || $color ==
                "orange" || $color == "aqua") {
                Imagettftext($image, 10, 0, $cur_line_x, $cur_line_y, getColor($color), getfont
                    ($font), trim($line));
 
 
            } elseif ($color != "white" || $color != "yellow" || $color != "green" || $color !=
            "orange" || $color != "aqua") {
                Imagettftext($image, 10, 0, $cur_line_x, $cur_line_y, $whit, getfont($font),
                    trim($line));
 
 
            } elseif ($font == "fixedsys" || $font == "Courbd" || $font == "arial" || $font ==
            "timesnr" || $font == "calibri" || $font == "comicsans" || $font == "palab") {
                Imagettftext($image, 10, 0, $cur_line_x, $cur_line_y, getColor($color), getfont
                    ($font), trim($line));
 
 
            } else {
                Imagettftext($image, 10, 0, $cur_line_x, $cur_line_y, $whit, "courbd.ttf", trim
                    ($line));
 
 
            }
 
 
        $cur_line_y += $lineheight;
 
 
        
 
  }
}
 
 if(!stristr($line, ":roll:"))  {
    header("Content-Type: image/png"); // tell the browser what we're gonna give it
    imagepng($image);
 imagepng($image, "./user/" . $user . $box. ".png");
 
} else {
    
     $pos = strpos($line, ":roll:");
 
        if ($font == "palab") {
            $post = $pos * 5.7;
        } elseif ($font == "comicsans") {
            $post = $pos * 6.725;
        } elseif ($font == "calibri") {
            $post = $pos * 5;
        } elseif ($font == "courbd") {
            $post = ($pos * 5.<!-- s8) --><img src=\"{SMILIES_PATH}/icon_cool.gif\" alt=\"8)\" title=\"Cool\" /><!-- s8) --> + 1;
        } elseif ($font == "arial") {
            $post = ($pos * 7.3) + 1;
        } else {
 
        }
    
 
            
      if ( $dh = opendir ( "frames/" ) ) {
 
    while ( false !== ( $dat = readdir ( $dh ) ) ) {
 
        if ( $dat != "." && $dat != ".." ) {
 
            $frames [ ] .= "frames/$dat";
 
            $framed [ ] = 17;
 
        }
 
    }
 
    closedir ( $dh );
 
}
   
    foreach( $frames as $thePfhrame )
   
      {
   
          $imgPfhrame = imagecreatefromgif($thePfhrame);
   
          imagecopymerge($image, $imgPfhrame, ($cur_line_x + $post) + 6, (($cur_line_y + $lineheight) - 30.5), 0, 0, 15, 15, 100);
   
          
          
        
      }
      
 
  $gif = new GIFAnimator    (
 
                            $frames, //sources - URL or path
 
                            $framed, //delay times - int
 
                            0, //Animation loops - int - 0 is infinite
 
                            2, //Disposal - int
 
                            -1, -1, -1, //transparency red, green, blue - int
 
                            "url" // source type
 
        );
   
   
    
 
       
 
        header("Content-Type: image/gif");
 
echo $gif->GetAnimation();
 
 
FWrite ( FOpen ( "helraizer2.gif", "wb" ), $gif->GetAnimation ( ) );
 
}
 
 
 
 
Hope that makes sense.

Sam
User avatar
Ollie Saunders
DevNet Master
Posts: 3179
Joined: Tue May 24, 2005 6:01 pm
Location: UK

Re: Animating gifs with GD

Post by Ollie Saunders »

I see a parse error around 101 but I'm not really willing to look through the whole thing. Bare in mind that's quite a lot to ask of forum contributers.
helraizer
Forum Commoner
Posts: 31
Joined: Thu Jun 05, 2008 8:20 pm

Re: Animating gifs with GD

Post by helraizer »

ole wrote:I see a parse error around 101 but I'm not really willing to look through the whole thing. Bare in mind that's quite a lot to ask of forum contributers.
I maybe didn't phrase it quite right. I was asking if they could point out any major errors/ones that stand out, that I may have missed. Not comb it detail by detail. Sorry if my post was vague.

Ooh, err. Not sure what's going on at 101. That must have been a copy and paste error, maybe I accidently dragged an emoticon or something into the code block, it's not actually in my code.

Sam
Post Reply