php2Bluesky: When is a GIF not a GIF?

A fairly unusual php2Bluesky issue was raised recently, via Github, where when a site was being used as a link card and the main image on that site was a GIF it was being converted and sent to Bluesky as a video, which it didn’t like.

Invalid app.bsky.feed.post record:
Expected "image/*" (got "video/mp4")
at $.record.embed.external.thumb.mimeType

I suppose that this makes sense – there can’t be many sites with a GIF as the associated image and Bluesky wouldn’t be expecting that.

What to do about it?

This presented an interesting challenge – just what should I do about it? The options seemed to be:

  1. throw an error and let whatever was calling php2Bluesky deal with it
  2. use the fallback option the user has provided on creating the php2Bluesky instance
  3. convert the GIF to something else

I chose to go with option three but I then needed to decide:

  1. what should I convert it to?
  2. which frame from the GIF should I use?
  3. what should I do about any transparency?

Stick with what you know

A fairly obvious way forward would have been to have used Imagick and done something like this:

$image = new Imagick($gifFile);

$image->setIteratorIndex(0);
$image->setImageBackgroundColor('white');
$image = $image->mergeImageLayers(Imagick::LAYERMETHOD_FLATTEN);

$image->setImageFormat('jpeg');
$image->setImageCompressionQuality(90);
$image->writeImage($outputFile);

$image->clear();
$image->destroy();

The problem with this was that it created a new dependency on php2Bluesky which I wanted to avoid. Given that ffmpeg is already a dependency that is required for converting GIFs to videos I decided to use this instead:

$cmd = sprintf(
    'ffmpeg -hide_banner -y -i %s -frames:v 1 %s 2>&1',
    escapeshellarg($gifFile),
    escapeshellarg($outputFile)
);

exec($cmd, $output, $returnCode);

This takes the first frame from the GIF and outputs it to a JPEG image, converting any transparency to white space.

To this end I have added two new functions: getffmpegPath() and convertGifToImage() which check if and where ffmpeg is installed and converts a passed GIF to an image respectively. The main process now checks to see if a link card has a GIF associated and calls convertGifToImage() to handle it.

Important note: you will need version 9 or above of ffmpeg (and ffprobe) for this to work. You can download the latest version for your machine here.

Another edge case sorted. As ever I am grateful for those users of php2Bluesky who have reported these issues so that I can get them resolved. If you are interested you can download the code from my Github page.

Leave a Reply

Your email address will not be published. Required fields are marked *