From 1d1490b06a1f5ecb10b3b98a72efc55d09c10944 Mon Sep 17 00:00:00 2001 From: Yassine Doghri <yassine@doghri.fr> Date: Wed, 8 Dec 2021 17:05:34 +0000 Subject: [PATCH] feat(video-clips): add new themes + add castopod logo as a watermark fix video colors to portray exact rgb values using libx264rgb encoding + image transparency issue when overlaying images with php gd --- .../MediaClipper/Config/MediaClipper.php | 116 +++++++++++++++++- app/Libraries/MediaClipper/VideoClip.php | 84 +++++++++---- app/Libraries/MediaClipper/castopod-logo.png | Bin 0 -> 2803 bytes .../Components/Forms/ColorRadioButton.php | 4 +- themes/cp_admin/episode/video_clips_new.php | 7 +- 5 files changed, 178 insertions(+), 33 deletions(-) create mode 100644 app/Libraries/MediaClipper/castopod-logo.png diff --git a/app/Libraries/MediaClipper/Config/MediaClipper.php b/app/Libraries/MediaClipper/Config/MediaClipper.php index c457185199..f4274d6de2 100644 --- a/app/Libraries/MediaClipper/Config/MediaClipper.php +++ b/app/Libraries/MediaClipper/Config/MediaClipper.php @@ -14,6 +14,8 @@ class MediaClipper extends BaseConfig public string $wavesMask = APPPATH . 'Libraries/MediaClipper/waves-mask.png'; + public string $watermark = APPPATH . 'Libraries/MediaClipper/castopod-logo.png'; + /** * @var array<string, array<string, int|array<string, float|int|string>>> */ @@ -57,9 +59,15 @@ class MediaClipper extends BaseConfig 'timestamp' => [ 'fontsize' => 32, 'padding' => 10, - 'x' => 1680, + 'x' => 1620, 'y' => 985, ], + 'watermark' => [ + 'width' => 90, + 'height' => 72, + 'x' => 140, + 'y' => 960, + ], 'progressbar' => [ 'height' => 10, ], @@ -117,10 +125,16 @@ class MediaClipper extends BaseConfig ], 'timestamp' => [ 'fontsize' => 48, - 'padding' => 10, - 'x' => 735, + 'padding' => 14, + 'x' => 734, 'y' => 1800, ], + 'watermark' => [ + 'width' => 120, + 'height' => 96, + 'x' => 130, + 'y' => 1770, + ], 'progressbar' => [ 'height' => 10, ], @@ -183,6 +197,12 @@ class MediaClipper extends BaseConfig 'x' => 855, 'y' => 1070, ], + 'watermark' => [ + 'width' => 120, + 'height' => 96, + 'x' => 130, + 'y' => 1040, + ], 'progressbar' => [ 'height' => 10, ], @@ -209,6 +229,8 @@ class MediaClipper extends BaseConfig */ public array $themes = [ 'pine' => [ + // Preview must be a HSL colorscheme string + 'preview' => '174 100% 29%', 'background' => [0, 86, 74], 'text' => [255, 255, 255], // subtitle hex color is BGR (Blue, Green, Red), @@ -220,7 +242,93 @@ class MediaClipper extends BaseConfig 'progressbar' => '009486', 'timestampBg' => '00564A', 'timestampText' => 'FFFFFF', - 'soundwaves' => 'F2FAF9', + 'watermarkBg' => '00564A', + 'soundwaves' => [231, 249, 228], + ], + 'crimson' => [ + // Preview must be a HSL colorscheme string + 'preview' => '350 87% 61%', + 'background' => [179, 31, 57], + 'text' => [255, 255, 255], + // subtitle hex color is BGR (Blue, Green, Red), + 'subtitles' => 'FFFFFF', + // quotes image MUST BE black + 'quotes' => [242, 70, 100], + 'episodeNumberingBg' => [152, 16, 43], + 'episodeNumberingText' => [255, 255, 255], + 'progressbar' => 'F24664', + 'timestampBg' => 'B31F39', + 'timestampText' => 'FFFFFF', + 'watermarkBg' => 'B31F39', + 'soundwaves' => [253, 206, 215], + ], + 'lake' => [ + // Preview must be a HSL colorscheme string + 'preview' => '194 100% 44%', + 'background' => [0, 86, 113], + 'text' => [255, 255, 255], + // subtitle hex color is BGR (Blue, Green, Red), + 'subtitles' => 'FFFFFF', + // quotes image MUST BE black + 'quotes' => [0, 171, 225], + 'episodeNumberingBg' => [0, 43, 57], + 'episodeNumberingText' => [255, 255, 255], + 'progressbar' => '00ABE1', + 'timestampBg' => '005671', + 'timestampText' => 'FFFFFF', + 'watermarkBg' => '005671', + 'soundwaves' => [214, 245, 255], + ], + 'amber' => [ + // Preview must be a HSL colorscheme string + 'preview' => '17 100% 57%', + 'background' => [177, 50, 0], + 'text' => [255, 255, 255], + // subtitle hex color is BGR (Blue, Green, Red), + 'subtitles' => 'FFFFFF', + // quotes image MUST BE black + 'quotes' => [255, 96, 34], + 'episodeNumberingBg' => [121, 34, 0], + 'episodeNumberingText' => [255, 255, 255], + 'progressbar' => 'FF6022', + 'timestampBg' => 'B13200', + 'timestampText' => 'FFFFFF', + 'watermarkBg' => 'B13200', + 'soundwaves' => [255, 213, 197], + ], + 'jacaranda' => [ + // Preview must be a HSL colorscheme string + 'preview' => '254 72% 52%', + 'background' => [47, 21, 132], + 'text' => [255, 255, 255], + // subtitle hex color is BGR (Blue, Green, Red), + 'subtitles' => 'FFFFFF', + // quotes image MUST BE black + 'quotes' => [86, 45, 221], + 'episodeNumberingBg' => [30, 14, 84], + 'episodeNumberingText' => [255, 255, 255], + 'progressbar' => '562DDD', + 'timestampBg' => '2F1584', + 'timestampText' => 'FFFFFF', + 'watermarkBg' => '2F1584', + 'soundwaves' => [199, 185, 244], + ], + 'onyx' => [ + // Preview must be a HSL colorscheme string + 'preview' => '240 17% 2%', + 'background' => [5, 5, 7], + 'text' => [255, 255, 255], + // subtitle hex color is BGR (Blue, Green, Red), + 'subtitles' => 'FFFFFF', + // quotes image MUST BE black + 'quotes' => [38, 38, 49], + 'episodeNumberingBg' => [0, 0, 0], + 'episodeNumberingText' => [255, 255, 255], + 'progressbar' => 'D5D5E1', + 'timestampBg' => '050507', + 'timestampText' => 'FFFFFF', + 'watermarkBg' => '050507', + 'soundwaves' => [213, 213, 225], ], ]; } diff --git a/app/Libraries/MediaClipper/VideoClip.php b/app/Libraries/MediaClipper/VideoClip.php index 909bd13e82..d1f11de5b9 100644 --- a/app/Libraries/MediaClipper/VideoClip.php +++ b/app/Libraries/MediaClipper/VideoClip.php @@ -13,6 +13,11 @@ namespace MediaClipper; use App\Entities\Episode; use GdImage; +/** + * TODO: refactor this by splitting image manipulations + video generation + * + * @phpstan-ignore-next-line + */ class VideoClip { /** @@ -44,21 +49,11 @@ class VideoClip protected ?string $episodeNumbering = null; - /** - * @var 'landscape'|'portrait'|'squared' - */ - protected string $format = 'landscape'; - /** * @var array<string, mixed> */ protected array $dimensions = []; - /** - * @var 'pine'|'crimson'|'lake'|'amber'|'jacaranda'|'onyx' - */ - protected string $theme = 'pine'; - /** * @var array<string, mixed> */ @@ -72,11 +67,10 @@ class VideoClip protected Episode $episode, protected float $start, protected float $end, - string $format, - string $theme, + protected string $format = 'landscape', + protected string $theme = 'pine', ) { $this->duration = $end - $start; - $this->format = $format; $this->episodeNumbering = $this->episodeNumbering($this->episode->number, $this->episode->season_number); $this->dimensions = config('MediaClipper') ->formats[$format]; @@ -95,8 +89,8 @@ class VideoClip $this->soundbiteOutput = $podcastFolder . "/{$this->episode->slug}-soundbite-{$this->start}-to-{$this->end}.mp3"; $this->subtitlesClipOutput = $podcastFolder . "/{$this->episode->slug}-subtitles-clip-{$this->start}-to-{$this->end}.srt"; - $this->videoClipBgOutput = $podcastFolder . "/{$this->episode->slug}-clip-bg-{$this->format}.png"; - $this->videoClipOutput = $podcastFolder . "/{$this->episode->slug}-clip-{$this->start}-to-{$this->end}-{$this->format}.mp4"; + $this->videoClipBgOutput = $podcastFolder . "/{$this->episode->slug}-clip-bg-{$this->format}-{$this->theme}.png"; + $this->videoClipOutput = $podcastFolder . "/{$this->episode->slug}-clip-{$this->start}-to-{$this->end}-{$this->format}-{$this->theme}.mp4"; } public function soundbite(): void @@ -132,23 +126,30 @@ class VideoClip { // @phpstan-ignore $filters = [ - "[0:a]aformat=channel_layouts=mono,showwaves=s={$this->dimensions['soundwaves']['width']}x{$this->dimensions['soundwaves']['height']}:mode=cline:rate=10:colors=0xFFFFFF,format=yuva420p[waves]", + "[0:a]aformat=channel_layouts=mono,showwaves=s={$this->dimensions['soundwaves']['width']}x{$this->dimensions['soundwaves']['height']}:mode=cline:rate=10:colors=white,format=rgb24[waves]", "[waves]scale={$this->dimensions['width']}:{$this->dimensions['height']}:flags=neighbor[resizedwaves]", '[resizedwaves][3:v][4:v][5:v]threshold[cleanwaves]', '[cleanwaves][2:v]alphamerge[waves_t]', '[4:v][waves_t]overlay=x=0:y=0:shortest=1[waves_t2]', '[waves_t2]split[m][a]', '[m][a]alphamerge[waves_t3]', - "[waves_t3]scale={$this->dimensions['soundwaves']['rescaleWidth']}:{$this->dimensions['soundwaves']['rescaleHeight']}[waves_final]", + "[waves_t3]scale={$this->dimensions['soundwaves']['rescaleWidth']}:{$this->dimensions['soundwaves']['rescaleHeight']},lutrgb=r='if(gt(val,100),{$this->colors['soundwaves'][0]},val)':g='if(gt(val,100),{$this->colors['soundwaves'][1]},val)':b='if(gt(val,100),{$this->colors['soundwaves'][2]},val)'[waves_final]", "[1:v][waves_final]overlay=x={$this->dimensions['soundwaves']['x']}:y={$this->dimensions['soundwaves']['y']}:shortest=1,drawtext=fontfile=" . $this->getFont( 'timestamp' - ) . ":text='%{pts\:gmtime\:{$this->start}\:%H\\\\\\\\\\:%M\\\\\\\\\\:%S\}':x={$this->dimensions['timestamp']['x']}:y={$this->dimensions['timestamp']['y']}:fontsize={$this->dimensions['timestamp']['fontsize']}:fontcolor=0x{$this->colors['timestampText']}:box=1:boxcolor=0x{$this->colors['timestampBg']}:boxborderw={$this->dimensions['timestamp']['padding']},format=yuv420p,colormatrix=bt601:bt2020[v3]", + ) . ":text='%{pts\:gmtime\:{$this->start}\:%H\\\\\\\\\\:%M\\\\\\\\\\:%S\}':x={$this->dimensions['timestamp']['x']}:y={$this->dimensions['timestamp']['y']}:fontsize={$this->dimensions['timestamp']['fontsize']}:fontcolor=0x{$this->colors['timestampText']}:box=1:boxcolor=0x{$this->colors['timestampBg']}:boxborderw={$this->dimensions['timestamp']['padding']}[v3]", "color=c=0x{$this->colors['progressbar']}:s={$this->dimensions['width']}x{$this->dimensions['progressbar']['height']}[progressbar]", "[v3][progressbar]overlay=-w+(w/{$this->duration})*t:0:shortest=1:format=rgb,subtitles={$this->subtitlesClipOutput}:fontsdir=" . config( 'MediaClipper' - )->fontsFolder . ":force_style='Fontname=" . self::FONTS['subtitles'] . ",Alignment=5,Fontsize={$this->dimensions['subtitles']['fontsize']},PrimaryColour=&H{$this->colors['subtitles']}&,BorderStyle=1,Outline=0,Shadow=0,MarginL={$this->dimensions['subtitles']['marginL']},MarginR={$this->dimensions['subtitles']['marginR']},MarginV={$this->dimensions['subtitles']['marginV']}',format=yuv420p,colormatrix=bt601:bt2020[outv]", + )->fontsFolder . ":force_style='Fontname=" . self::FONTS['subtitles'] . ",Alignment=5,Fontsize={$this->dimensions['subtitles']['fontsize']},PrimaryColour=&H{$this->colors['subtitles']}&,BorderStyle=1,Outline=0,Shadow=0,MarginL={$this->dimensions['subtitles']['marginL']},MarginR={$this->dimensions['subtitles']['marginR']},MarginV={$this->dimensions['subtitles']['marginV']}'[outv]", + "[6:v]scale={$this->dimensions['watermark']['width']}:{$this->dimensions['watermark']['height']}[watermark]", + "color=0x{$this->colors['watermarkBg']}:{$this->dimensions['watermark']['width']}x{$this->dimensions['watermark']['height']}[over]", + '[over][watermark]overlay=x=0:y=0:shortest=1[watermark_box]', + "[outv][watermark_box]overlay=x={$this->dimensions['watermark']['x']}:y={$this->dimensions['watermark']['y']}:shortest=1[watermarked]", ]; + $watermark = config('MediaClipper') + ->watermark; + $videoClipCmd = [ 'ffmpeg -y', "-i {$this->soundbiteOutput}", @@ -156,13 +157,13 @@ class VideoClip "-loop 1 -framerate 30 -i {$this->dimensions['soundwaves']['mask']}", "-f lavfi -i color=gray:{$this->dimensions['width']}x{$this->dimensions['height']}", "-f lavfi -i color=black:{$this->dimensions['width']}x{$this->dimensions['height']}", - "-f lavfi -i color=0x{$this->colors['soundwaves']}:{$this->dimensions['width']}x{$this->dimensions['height']}", + "-f lavfi -i color=white:{$this->dimensions['width']}x{$this->dimensions['height']}", + "-loop 1 -framerate 1 -i {$watermark}", '-filter_complex "' . implode(';', $filters) . '"', - '-map "[outv]"', + '-map "[watermarked]"', '-map 0:a', '-acodec copy', - '-vcodec libx264', - '-pix_fmt yuv420p', + '-vcodec libx264rgb', "{$this->videoClipOutput}", ]; @@ -306,10 +307,16 @@ class VideoClip return false; } - imagefilter($quotes, IMG_FILTER_COLORIZE, ...$this->colors['quotes']); + $cleanedQuotes = $this->cleanTransparency($quotes); + + if (! $cleanedQuotes) { + return false; + } + imagefilter($cleanedQuotes, IMG_FILTER_CONTRAST, 255); + imagefilter($cleanedQuotes, IMG_FILTER_COLORIZE, ...$this->colors['quotes']); $scaledQuotes = $this->scaleImage( - $quotes, + $cleanedQuotes, $this->dimensions['quotes']['width'], $this->dimensions['quotes']['height'] ); @@ -318,6 +325,7 @@ class VideoClip return false; } + imagesavealpha($scaledQuotes, true); $this->overlayImages( $background, $scaledQuotes, @@ -570,6 +578,32 @@ class VideoClip return true; } + /** + * This helps getting a truly transparent background for images with transparency: + * https://stackoverflow.com/a/2611911 + */ + private function cleanTransparency(GdImage $image): GdImage | false + { + $imageBg = imagecolorallocate($image, 0, 0, 0); + if ($imageBg === false) { + return false; + } + + // removing the black from the image + imagecolortransparent($image, $imageBg); + + // turning off alpha blending (to ensure alpha channel information + // is preserved, rather than removed (blending with the rest of the + // image in the form of black)) + imagealphablending($image, false); + + // turning on alpha channel information saving (to ensure the full range + // of transparency is preserved) + imagesavealpha($image, true); + + return $image; + } + /** * @return array<int, string>|false */ diff --git a/app/Libraries/MediaClipper/castopod-logo.png b/app/Libraries/MediaClipper/castopod-logo.png new file mode 100644 index 0000000000000000000000000000000000000000..fa6544aaa2087553e12aa7f77e084429f7d3abbb GIT binary patch literal 2803 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 literal 0 HcmV?d00001 diff --git a/app/Views/Components/Forms/ColorRadioButton.php b/app/Views/Components/Forms/ColorRadioButton.php index 906eb69329..a3454f54ba 100644 --- a/app/Views/Components/Forms/ColorRadioButton.php +++ b/app/Views/Components/Forms/ColorRadioButton.php @@ -8,6 +8,8 @@ class ColorRadioButton extends FormComponent { protected bool $isChecked = false; + protected string $style = ''; + public function setIsChecked(string $value): void { $this->isChecked = $value === 'true'; @@ -26,7 +28,7 @@ class ColorRadioButton extends FormComponent ); return <<<HTML - <div class="{$this->class}"> + <div class="{$this->class}" style="{$this->style}"> {$radioInput} <label for="{$this->value}" title="{$this->slot}" data-tooltip="bottom"></label> </div> diff --git a/themes/cp_admin/episode/video_clips_new.php b/themes/cp_admin/episode/video_clips_new.php index abcb48b22a..93ce42a0f2 100644 --- a/themes/cp_admin/episode/video_clips_new.php +++ b/themes/cp_admin/episode/video_clips_new.php @@ -29,12 +29,13 @@ </fieldset> <div class="grid gap-4 grid-cols-colorButtons"> - <?php foreach (config('Colors')->themes as $themeName => $color): ?> + <?php foreach (config('MediaClipper')->themes as $themeName => $colors): ?> <Forms.ColorRadioButton - class="theme-<?= $themeName ?> mx-auto" + class="mx-auto" value="<?= $themeName ?>" name="theme" - isChecked="<?= $themeName === 'pine' ? 'true' : 'false' ?>" ><?= lang('Settings.theme.' . $themeName) ?></Forms.ColorRadioButton> + isChecked="<?= $themeName === 'pine' ? 'true' : 'false' ?>" + style="--color-accent-base: <?= $colors['preview']?>"><?= lang('Settings.theme.' . $themeName) ?></Forms.ColorRadioButton> <?php endforeach; ?> </div> -- GitLab