OG image creation improved

This commit is contained in:
hbrain 2026-06-04 10:39:04 +02:00
parent cb126a1ca1
commit 947b509f0b

91
new.php
View file

@ -49,7 +49,8 @@ function slugify($s){ $s = ascii_safe($s); $s = strtolower(trim($s)); $s = preg_
function rrmdir($dir){ if(!is_dir($dir)) return; foreach(scandir($dir) as $f){ if($f==='.'||$f==='..') continue; $p="$dir/$f"; is_dir($p)?rrmdir($p):unlink($p);} rmdir($dir); } function rrmdir($dir){ if(!is_dir($dir)) return; foreach(scandir($dir) as $f){ if($f==='.'||$f==='..') continue; $p="$dir/$f"; is_dir($p)?rrmdir($p):unlink($p);} rmdir($dir); }
function apply_thumbnail_overlay($imagePath, $title, $teaser) { function apply_thumbnail_overlay($imagePath, $title, $teaser) {
$logFile = __DIR__ . '/logs/image_magick.log'; $logFile = __DIR__ . '/logs/image_magick.log';
file_put_contents($logFile, "--- New Thumbnail Job ---\n", FILE_APPEND); file_put_contents($logFile, "--- New Thumbnail Job ---
", FILE_APPEND);
$fontPath = __DIR__ . '/assets/fonts/IBMPlexSans-SemiBold.ttf'; $fontPath = __DIR__ . '/assets/fonts/IBMPlexSans-SemiBold.ttf';
$titleFontPath = is_file(__DIR__ . '/assets/fonts/BebasNeue-Regular.ttf') $titleFontPath = is_file(__DIR__ . '/assets/fonts/BebasNeue-Regular.ttf')
@ -62,8 +63,13 @@ function apply_thumbnail_overlay($imagePath, $title, $teaser) {
throw new RuntimeException('Thumbnail font file is missing.'); throw new RuntimeException('Thumbnail font file is missing.');
} }
$imgW = 1200; $scale = 3;
$imgH = 630; $baseW = 1200;
$baseH = 630;
$imgW = $baseW * $scale;
$imgH = $baseH * $scale;
$targetW = $baseW;
$targetH = $baseH;
$normalize = static function ($text): string { $normalize = static function ($text): string {
$text = trim((string)$text); $text = trim((string)$text);
@ -73,7 +79,8 @@ function apply_thumbnail_overlay($imagePath, $title, $teaser) {
}; };
$wrapText = static function ($text, int $width) use ($normalize): string { $wrapText = static function ($text, int $width) use ($normalize): string {
$text = $normalize($text); $text = $normalize($text);
return $text === '' ? '' : wordwrap($text, $width, "\n", false); return $text === '' ? '' : wordwrap($text, $width, "
", false);
}; };
$clampWrappedText = static function ($text, int $width, int $maxLines, bool $cutLongWords = false) use ($normalize): string { $clampWrappedText = static function ($text, int $width, int $maxLines, bool $cutLongWords = false) use ($normalize): string {
$text = $normalize($text); $text = $normalize($text);
@ -82,8 +89,10 @@ function apply_thumbnail_overlay($imagePath, $title, $teaser) {
if (!$words) return ''; if (!$words) return '';
$candidate = implode(' ', $words); $candidate = implode(' ', $words);
while (true) { while (true) {
$wrapped = wordwrap($candidate, $width, "\n", $cutLongWords); $wrapped = wordwrap($candidate, $width, "
$lineCount = substr_count($wrapped, "\n") + 1; ", $cutLongWords);
$lineCount = substr_count($wrapped, "
") + 1;
if ($lineCount <= $maxLines || count($words) <= 1) return $wrapped; if ($lineCount <= $maxLines || count($words) <= 1) return $wrapped;
array_pop($words); array_pop($words);
$candidate = implode(' ', $words) . '…'; $candidate = implode(' ', $words) . '…';
@ -97,7 +106,8 @@ function apply_thumbnail_overlay($imagePath, $title, $teaser) {
for ($size = 84; $size >= 54; $size -= 4) { for ($size = 84; $size >= 54; $size -= 4) {
$width = max(16, min(46, (int)round(23 + (84 - $size) / 2.7))); $width = max(16, min(46, (int)round(23 + (84 - $size) / 2.7)));
$candidate = $wrapText($text, $width); $candidate = $wrapText($text, $width);
$lines = substr_count($candidate, "\n") + 1; $lines = substr_count($candidate, "
") + 1;
$bestText = $candidate; $bestText = $candidate;
$bestSize = $size; $bestSize = $size;
$bestWidth = $width; $bestWidth = $width;
@ -107,15 +117,28 @@ function apply_thumbnail_overlay($imagePath, $title, $teaser) {
return [$bestText, $bestSize, $bestWidth, $bestLines]; return [$bestText, $bestSize, $bestWidth, $bestLines];
}; };
[$titleText, $titleFontSize, $titleWrapWidth, $titleLines] = $fitTitleText($title); [$titleText, $titleFontSizeBase, $titleWrapWidth, $titleLines] = $fitTitleText($title);
$teaserText = $clampWrappedText($teaser, 34, 6, true); $teaserText = $clampWrappedText($teaser, 34, 6, true);
$teaserLines = max(1, substr_count($teaserText, "\n") + 1); $teaserLines = max(1, substr_count($teaserText, "
") + 1);
// Move the whole block a bit left and higher while keeping left-aligned text. $baseLeft = max(14, (int)round($baseW * 0.046));
$left = max(14, (int)round($imgW * 0.046)); $baseTitleY = max(20, (int)round($baseH * 0.062));
$titleY = max(20, (int)round($imgH * 0.062)); $baseTitleLineStep = max(68, (int)round($baseH * 0.043));
$titleLineStep = max(68, (int)round($imgH * 0.043)); $baseTeaserY = max((int)round($baseH * 0.235), $baseTitleY + ($titleLines * $baseTitleLineStep) + max(54, (int)round($baseH * 0.03)));
$teaserY = max((int)round($imgH * 0.235), $titleY + ($titleLines * $titleLineStep) + max(54, (int)round($imgH * 0.03)));
$left = $baseLeft * $scale;
$titleY = $baseTitleY * $scale;
$titleLineStep = $baseTitleLineStep * $scale;
$teaserY = $baseTeaserY * $scale;
$shadowOffset = 3 * $scale;
$titleLineSpacing = 2 * $scale;
$teaserLineSpacing = -18 * $scale;
$titlePointSize = $titleFontSizeBase * $scale;
$teaserPointSize = 58 * $scale;
$shadowFill = 'rgba(0,0,0,0.35)';
$titleFill = '#F3F4F6';
$teaserFill = '#EADFC9';
$overlayBase = tempnam(sys_get_temp_dir(), 'thumb_overlay_'); $overlayBase = tempnam(sys_get_temp_dir(), 'thumb_overlay_');
$outputPath = dirname($imagePath) . '/' . basename($imagePath) . '.tmp.' . uniqid('', true) . '.jpg'; $outputPath = dirname($imagePath) . '/' . basename($imagePath) . '.tmp.' . uniqid('', true) . '.jpg';
@ -126,23 +149,38 @@ function apply_thumbnail_overlay($imagePath, $title, $teaser) {
@unlink($overlayBase); @unlink($overlayBase);
$cmd1 = sprintf( $cmd1 = sprintf(
'/usr/bin/convert -size %dx%d xc:none -font %s -pointsize %d -fill "#F3F4F6" -stroke black -strokewidth 2 -interline-spacing 2 -gravity northwest -annotate +%d+%d %s -font %s -pointsize 58 -fill "#EADFC9" -stroke black -strokewidth 2 -interline-spacing -18 -gravity northwest -annotate +%d+%d %s %s 2>&1', '/usr/bin/convert -size %dx%d xc:none -font %s -pointsize %d -fill %s -interline-spacing %d -gravity northwest -annotate +%d+%d %s -fill %s -annotate +%d+%d %s -font %s -pointsize %d -fill %s -interline-spacing %d -gravity northwest -annotate +%d+%d %s -fill %s -annotate +%d+%d %s %s 2>&1',
$imgW, $imgW,
$imgH, $imgH,
escapeshellarg($titleFontPath), escapeshellarg($titleFontPath),
$titleFontSize, $titlePointSize,
escapeshellarg($shadowFill),
$titleLineSpacing,
$left + $shadowOffset,
$titleY + $shadowOffset,
escapeshellarg($titleText),
escapeshellarg($titleFill),
$left, $left,
$titleY, $titleY,
escapeshellarg($titleText), escapeshellarg($titleText),
escapeshellarg($teaserFontPath), escapeshellarg($teaserFontPath),
$teaserPointSize,
escapeshellarg($shadowFill),
$teaserLineSpacing,
$left + $shadowOffset,
$teaserY + $shadowOffset,
escapeshellarg($teaserText),
escapeshellarg($teaserFill),
$left, $left,
$teaserY, $teaserY,
escapeshellarg($teaserText), escapeshellarg($teaserText),
escapeshellarg($overlayPath) escapeshellarg($overlayPath)
); );
file_put_contents($logFile, "Overlay CMD: " . $cmd1 . "\n", FILE_APPEND); file_put_contents($logFile, "Overlay CMD: " . $cmd1 . "
", FILE_APPEND);
$out1 = shell_exec($cmd1); $out1 = shell_exec($cmd1);
file_put_contents($logFile, "Overlay Output: " . $out1 . "\n", FILE_APPEND); file_put_contents($logFile, "Overlay Output: " . $out1 . "
", FILE_APPEND);
if (!is_file($overlayPath) || filesize($overlayPath) < 100) { if (!is_file($overlayPath) || filesize($overlayPath) < 100) {
@unlink($overlayPath); @unlink($overlayPath);
@unlink($outputPath); @unlink($outputPath);
@ -150,7 +188,7 @@ function apply_thumbnail_overlay($imagePath, $title, $teaser) {
} }
$maxBytes = 600 * 1024; $maxBytes = 600 * 1024;
$qualities = [88, 84, 80, 76, 72, 68, 64, 60, 56, 52, 48]; $qualities = [96, 92, 88, 84, 80, 76, 72, 68, 64];
$finalPath = ''; $finalPath = '';
$finalSize = 0; $finalSize = 0;
$finalOut = ''; $finalOut = '';
@ -158,19 +196,25 @@ function apply_thumbnail_overlay($imagePath, $title, $teaser) {
foreach ($qualities as $quality) { foreach ($qualities as $quality) {
$attemptPath = dirname($imagePath) . '/' . basename($imagePath) . '.tmp.' . uniqid('', true) . '.jpg'; $attemptPath = dirname($imagePath) . '/' . basename($imagePath) . '.tmp.' . uniqid('', true) . '.jpg';
$cmd2 = sprintf( $cmd2 = sprintf(
'/usr/bin/convert -filter Lanczos -define filter:blur=0.85 %s -resize %dx%d^ -gravity center -extent %dx%d -modulate 70,82 %s -composite -strip -interlace Plane -sampling-factor 4:2:0 -quality %d %s 2>&1', '/usr/bin/convert -filter Lanczos -define filter:blur=0.85 %s -resize %dx%d^ -gravity center -extent %dx%d -modulate 70,82 %s -composite -resize %dx%d -gravity center -extent %dx%d -unsharp 0x0.75+0.75+0.008 -strip -interlace Plane -sampling-factor 4:2:0 -quality %d %s 2>&1',
escapeshellarg($imagePath), escapeshellarg($imagePath),
$imgW, $imgW,
$imgH, $imgH,
$imgW, $imgW,
$imgH, $imgH,
escapeshellarg($overlayPath), escapeshellarg($overlayPath),
$targetW,
$targetH,
$targetW,
$targetH,
$quality, $quality,
escapeshellarg($attemptPath) escapeshellarg($attemptPath)
); );
file_put_contents($logFile, "Composite CMD (q=$quality): " . $cmd2 . "\n", FILE_APPEND); file_put_contents($logFile, "Composite CMD (q=$quality): " . $cmd2 . "
", FILE_APPEND);
$out2 = shell_exec($cmd2); $out2 = shell_exec($cmd2);
file_put_contents($logFile, "Composite Output (q=$quality): " . $out2 . "\n", FILE_APPEND); file_put_contents($logFile, "Composite Output (q=$quality): " . $out2 . "
", FILE_APPEND);
if (!is_file($attemptPath) || filesize($attemptPath) < 100) { if (!is_file($attemptPath) || filesize($attemptPath) < 100) {
@unlink($attemptPath); @unlink($attemptPath);
@ -191,7 +235,8 @@ function apply_thumbnail_overlay($imagePath, $title, $teaser) {
} }
if ($finalSize > $maxBytes) { if ($finalSize > $maxBytes) {
file_put_contents($logFile, "Thumbnail still above size limit: " . $finalSize . " bytes\n", FILE_APPEND); file_put_contents($logFile, "Thumbnail still above size limit: " . $finalSize . " bytes
", FILE_APPEND);
} }
if (!@rename($finalPath, $imagePath)) { if (!@rename($finalPath, $imagePath)) {