OG image creation improved
This commit is contained in:
parent
cb126a1ca1
commit
947b509f0b
1 changed files with 68 additions and 23 deletions
91
new.php
91
new.php
|
|
@ -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)) {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue