From b7cf60c7b4400779bdca29c22a8e5f949f227009 Mon Sep 17 00:00:00 2001 From: tenma Date: Thu, 13 Aug 2020 18:46:54 +0100 Subject: [PATCH] [FFmpeg] Add FFmpeg plugin FFmpeg plugin serves as a better performant/quality alternative to resize animated GIFs than the ImageMagick plugin. --- plugins/FFmpeg/FFmpegPlugin.php | 151 ++++++++++++++++++ plugins/FFmpeg/README.md | 19 +++ plugins/FFmpeg/locale/FFmpeg.pot | 23 +++ .../FFmpeg/locale/en_GB/LC_MESSAGES/FFmpeg.po | 24 +++ .../FFmpeg/locale/pt/LC_MESSAGES/FFmpeg.po | 23 +++ 5 files changed, 240 insertions(+) create mode 100644 plugins/FFmpeg/FFmpegPlugin.php create mode 100644 plugins/FFmpeg/README.md create mode 100644 plugins/FFmpeg/locale/FFmpeg.pot create mode 100644 plugins/FFmpeg/locale/en_GB/LC_MESSAGES/FFmpeg.po create mode 100644 plugins/FFmpeg/locale/pt/LC_MESSAGES/FFmpeg.po diff --git a/plugins/FFmpeg/FFmpegPlugin.php b/plugins/FFmpeg/FFmpegPlugin.php new file mode 100644 index 0000000000..d57592fb22 --- /dev/null +++ b/plugins/FFmpeg/FFmpegPlugin.php @@ -0,0 +1,151 @@ +. + +/** + * Animated GIF resize support via PHP-FFMpeg + * + * @package GNUsocial + * @author Bruno Casteleiro + * @copyright 2020 Free Software Foundation, Inc http://www.fsf.org + * @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later + * @link http://www.gnu.org/software/social/ + */ + +defined('GNUSOCIAL') || die(); + +class FFmpegPlugin extends Plugin +{ + const PLUGIN_VERSION = '0.1.0'; + + public function onStartResizeImageFile(ImageFile $imagefile, string $outpath, array $box): bool + { + switch ($imagefile->mimetype) { + case 'image/gif': + // resize only if an animated GIF + if ($imagefile->animated) { + return !$this->resizeImageFileAnimatedGif($imagefile, $outpath, $box); + } + break; + } + return true; + } + + /** + * High quality GIF conversion. + * + * @see http://blog.pkh.me/p/21-high-quality-gif-with-ffmpeg.html + * @see https://github.com/PHP-FFMpeg/PHP-FFMpeg/pull/592 + */ + public function resizeImageFileAnimatedGif(ImageFile $imagefile, string $outpath, array $box): bool + { + // Create FFMpeg instance + // Need to explictly tell the drivers location or it won't find them + $ffmpeg = FFMpeg\FFMpeg::create([ + 'ffmpeg.binaries' => exec("which ffmpeg"), + 'ffprobe.binaries' => exec("which ffprobe") + ]); + + // FFmpeg can't edit existing files in place, + // generate temporary output file to avoid that + $tmp_outpath = tempnam(sys_get_temp_dir(), 'outpath-'); + + // Generate palette file. FFmpeg explictly needs to be told the + // extension for PNG files outputs + $palette = $this->tempnam_sfx(sys_get_temp_dir(), '.png'); + + // Build filters + $filters = 'fps=30'; + $filters .= ",crop={$box['w']}:{$box['h']}:{$box['x']}:{$box['y']}"; + $filters .= ",scale={$box['width']}:{$box['height']}:flags=lanczos"; + + // Assemble commands for palette generation + $commands[] = $commands_2[] = '-f'; + $commands[] = $commands_2[] = 'gif'; + $commands[] = $commands_2[] = '-i'; + $commands[] = $commands_2[] = $imagefile->filepath; + $commands[] = '-vf'; + $commands[] = $filters . ',palettegen'; + $commands[] = '-y'; + $commands[] = $palette; + + // Assemble commands for GIF generation + $commands_2[] = '-i'; + $commands_2[] = $palette; + $commands_2[] = '-lavfi'; + $commands_2[] = $filters . ' [x]; [x][1:v] paletteuse'; + $commands_2[] = '-f'; + $commands_2[] = 'gif'; + $commands_2[] = '-y'; + $commands_2[] = $tmp_outpath; + + $success = true; + + // Generate the palette image + try { + $ffmpeg->getFFMpegDriver()->command($commands); + } catch (Exception $e) { + $this->log(LOG_ERR, 'Unable to generate the palette image'); + $success = false; + } + + // Generate GIF + try { + if ($success) { + $ffmpeg->getFFMpegDriver()->command($commands_2); + } + } catch (Exception $e) { + $this->log(LOG_ERR, 'Unable to generate the GIF image'); + $success = false; + } + + if ($success) { + $success = @rename($tmp_outpath, $outpath); + } + + @unlink($tmp_outpath); + @unlink($palette); + + return $success; + } + + /** + * Suffix version of tempnam. + * Courtesy of tomas at slax dot org: + * @see https://www.php.net/manual/en/function.tempnam.php#98232 + */ + private function tempnam_sfx(string $dir, string $suffix): string + { + do { + $file = $dir . "/" . mt_rand() . $suffix; + $fp = @fopen($file, 'x'); + } while (!$fp); + + fclose($fp); + return $file; + } + + public function onPluginVersion(array &$versions): bool + { + $versions[] = ['name' => 'FFmpeg', + 'version' => self::PLUGIN_VERSION, + 'author' => 'Bruno Casteleiro', + 'homepage' => 'https://notabug.org/diogo/gnu-social/src/nightly/plugins/FFmpeg', + 'rawdescription' => + // TRANS: Plugin description. + _m('Use PHP-FFMpeg for resizing animated GIFs')]; + return true; + } +} diff --git a/plugins/FFmpeg/README.md b/plugins/FFmpeg/README.md new file mode 100644 index 0000000000..66c74ab15f --- /dev/null +++ b/plugins/FFmpeg/README.md @@ -0,0 +1,19 @@ +# FFmpeg plugin for GNU social +(c) 2020 Free Software Foundation, Inc + +This is the README file for GNU social's ActivityPub plugin. +It includes general information about the plugin. + +## About + +This plugin adds FFmpeg support to GNU social via PHP-FFMpeg. + +Currently it serves as a better performant and quality alternative to resize +animated GIFs than the ImageMagick plugin. However, it has the downside of +increasing a little the size of the original GIF images for some conversions. + +## Settings + +Make sure you've set the `upload_max_filesize` and `post_max_size` in php.ini +to be large enough to handle uploads if you ever experience some error with +fetching remote images. \ No newline at end of file diff --git a/plugins/FFmpeg/locale/FFmpeg.pot b/plugins/FFmpeg/locale/FFmpeg.pot new file mode 100644 index 0000000000..023e887f6e --- /dev/null +++ b/plugins/FFmpeg/locale/FFmpeg.pot @@ -0,0 +1,23 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# FIRST AUTHOR , YEAR. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2020-08-13 03:09+0100\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME \n" +"Language-Team: LANGUAGE \n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=CHARSET\n" +"Content-Transfer-Encoding: 8bit\n" + +#. TRANS: Plugin description. +#: FFmpegPlugin.php:104 +msgid "Use PHP-FFMpeg for resizing animated GIFs" +msgstr "" diff --git a/plugins/FFmpeg/locale/en_GB/LC_MESSAGES/FFmpeg.po b/plugins/FFmpeg/locale/en_GB/LC_MESSAGES/FFmpeg.po new file mode 100644 index 0000000000..51f3e15f22 --- /dev/null +++ b/plugins/FFmpeg/locale/en_GB/LC_MESSAGES/FFmpeg.po @@ -0,0 +1,24 @@ +# Translation file for GNU social - the free software social networking platform +# Copyright (C) 2015 - 2019 Free Software Foundation, Inc http://www.fsf.org +# This file is under https://www.gnu.org/licenses/agpl v3 or later +# +# Translators: +# Bruno Casteleiro , 2020 +msgid "" +msgstr "" +"Project-Id-Version: GNU social\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2020-08-13 18:21+0100\n" +"PO-Revision-Date: 2020-08-13 18:21+0100\n" +"Last-Translator: Bruno Casteleiro \n" +"Language-Team: English (United Kingdom) (http://www.transifex.com/gnu-social/gnu-social/language/en_GB/)\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Language: en_GB\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#. TRANS: Plugin description. +#: FFmpegPlugin.php:104 +msgid "Use PHP-FFMpeg for resizing animated GIFs" +msgstr "Use PHP-FFMpeg for resizing animated GIFs" \ No newline at end of file diff --git a/plugins/FFmpeg/locale/pt/LC_MESSAGES/FFmpeg.po b/plugins/FFmpeg/locale/pt/LC_MESSAGES/FFmpeg.po new file mode 100644 index 0000000000..78a676b059 --- /dev/null +++ b/plugins/FFmpeg/locale/pt/LC_MESSAGES/FFmpeg.po @@ -0,0 +1,23 @@ +# Copyright (C) 2020 Free Software Foundation, Inc http://www.fsf.org +# This file is under https://www.gnu.org/licenses/agpl v3 or later +# +# Translators: +# Bruno Casteleiro , 2020 +msgid "" +msgstr "" +"Project-Id-Version: GNU social\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2020-08-13 18:20+0100\n" +"PO-Revision-Date: 2019-08-13 18:20+0100\n" +"Last-Translator: Bruno Casteleiro \n" +"Language-Team: Portuguese (http://www.transifex.com/gnu-social/gnu-social/language/pt/)\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Language: pt\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#. TRANS: Plugin description. +#: FFmpegPlugin.php:104 +msgid "Use PHP-FFMpeg for resizing animated GIFs" +msgstr "Utiliza PHP-FFMpeg para redimensionar GIFs animados" \ No newline at end of file