I am trying to create animated gifs from youtube videos for my website, that will contain video information, I want to clone each frame, crop it, blur it and composite it to a certain location, I have the image animating, but the cloned sections aren't, it's like it's cloning the first frame then compositing it to all of the frames, I am using the following code
$img = "{$dir}{$vidInfo->id}.gif";
if( !file_exists($img) ) {
$grabzIt->SetAnimationOptions("https://www.youtube.com/watch?v={$vidInfo->id}", "{$vidInfo->id}", 320, 180, 0, 5, 2, 10, 0, false, '', 100, "UK");
$grabzIt->SaveTo($img);
}
$image = new Imagick($img);
$image = $image->coalesceImages();
foreach( $image as $frame ) {
$blurred = clone $frame;
$blurred->cropImage(360, 180, 241, 60);
$blurred->blurImage(5,3);
$frame->compositeImage($blurred, imagick::COMPOSITE_OVER, 241, 60);
$blurred = clone $frame;
$blurred->cropImage(320, 20, 0, 0);
$blurred->blurImage(5,3);
$frame->compositeImage($blurred, imagick::COMPOSITE_OVER, 0, 0);
$blurred = clone $frame;
$blurred->cropImage(320, 20, 0, 160);
$blurred->blurImage(5,3);
$frame->compositeImage($blurred, imagick::COMPOSITE_OVER, 0, 160);
}
$image = $image->deconstructImages();
$image->writeImages("{$dir}{$vidInfo->id}_final.gif", true);
echo $image->getImagesBlob();
but it comes out like this (notice the blurred areas are static)
I'm not sure what else to do, I have found a few examples, but they don't work for what I am trying to do, I have even tried
$blurred->clear();
$blurred->destroy();
after each frame, but that doesn't seem to work either.
any help would be much appreciated, Thankyou
It looks like there is a 'bug'* in the foreach implementation of Imagick. When you do this:
foreach ($animationImagick as $frameImagick) {
//whatever
}
The $frameImagick
object isn't actually a single frame, instead it's a copy of the whole animation with the internal iterator set to the appropriate frame for the animation.
Because of this, when you go to composite that 'frame image' back into the original image, ImageMagick sees that it's an image with multiple internal images and resets the internal iterator again. This leads to the first frame being pasted all the time.
Explicitly separating the frame image from the animation set of images solves this problem. Additionally not modifying the data you're iterating over is a sensible thing to do. This code does both
$image = new Imagick("./SeriouslyBurned.gif");
$image = $image->coalesceImages();
$newImageFrames = [];
$numberImages = $image->getNumberImages();
$outputImage = new Imagick();
foreach ($image as $frame) {
$frame = $frame->getImage();
$blurred = clone $frame;
$blurred->cropImage(360, 180, 241, 60);
$blurred->blurImage(5,3);
$frame->compositeImage($blurred, imagick::COMPOSITE_OVER, 241, 60);
$blurred = clone $frame;
$blurred->cropImage(320, 20, 0, 0);
$blurred->blurImage(5,3);
$frame->compositeImage($blurred, imagick::COMPOSITE_OVER, 0, 0);
$blurred = clone $frame;
$blurred->cropImage(320, 20, 0, 160);
$blurred->blurImage(5,3);
$frame->compositeImage($blurred, imagick::COMPOSITE_OVER, 0, 160);
$outputImage->addImage($frame);
}
$outputImage->setImageFormat('gif');
$outputImage->writeImages("output_file.gif", true);
*It's probably technically not a bug...as the code is doing what it was told to do. It's just not what anyone really wants....