chg: dev: remove the wrongly implemented font installation in docker - & replace it with static font on BattleCardGenerator (it solves the shareable image problem on bare-metal too) #8
This commit is contained in:
@@ -22,12 +22,6 @@ RUN install-php-extensions \
|
|||||||
apcu \
|
apcu \
|
||||||
sodium
|
sodium
|
||||||
|
|
||||||
RUN apt-get update && apt-get install -y --no-install-recommends \
|
|
||||||
fonts-dejavu-core \
|
|
||||||
fontconfig \
|
|
||||||
&& fc-cache -f -v \
|
|
||||||
&& rm -rf /var/lib/apt/lists/*
|
|
||||||
|
|
||||||
RUN mv "$PHP_INI_DIR/php.ini-production" "$PHP_INI_DIR/php.ini"
|
RUN mv "$PHP_INI_DIR/php.ini-production" "$PHP_INI_DIR/php.ini"
|
||||||
RUN printf '[opcache]\nopcache.enable=1\nopcache.memory_consumption=256\nopcache.max_accelerated_files=20000\nopcache.validate_timestamps=0\n' \
|
RUN printf '[opcache]\nopcache.enable=1\nopcache.memory_consumption=256\nopcache.max_accelerated_files=20000\nopcache.validate_timestamps=0\n' \
|
||||||
> "$PHP_INI_DIR/conf.d/opcache.ini"
|
> "$PHP_INI_DIR/conf.d/opcache.ini"
|
||||||
|
|||||||
@@ -287,11 +287,12 @@ git push origin v2026.01
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Game Documentation
|
## Documentation
|
||||||
|
|
||||||
For detailed information about game mechanics, bonus systems, and scoring rules, see the [docs](./docs/) directory:
|
For detailed information about game mechanics, bonus systems, fonts, and other technical details, see the [docs](./docs/) directory:
|
||||||
|
|
||||||
- **[Bonus Points System](./docs/game-mechanics/BONUS_POINTS_SYSTEM.md)** — Complete reference for all bonus point types, calculation rules, and implementation details
|
- **[Bonus Points System](./docs/game-mechanics/BONUS_POINTS_SYSTEM.md)** — Complete reference for all bonus point types, calculation rules, and implementation details
|
||||||
|
- **[Fonts](./docs/FONTS.md)** — TrueType fonts used for server-side image generation
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
BIN
assets/fonts/Carlito-Bold.ttf
Normal file
BIN
assets/fonts/Carlito-Bold.ttf
Normal file
Binary file not shown.
@@ -12,7 +12,9 @@ import { array } from 'prop-types';
|
|||||||
import { formatDuration } from '@global-utils/format';
|
import { formatDuration } from '@global-utils/format';
|
||||||
import Dialog from '@mui/material/Dialog';
|
import Dialog from '@mui/material/Dialog';
|
||||||
import { createTheme, styled, ThemeProvider } from '@mui/material/styles';
|
import { createTheme, styled, ThemeProvider } from '@mui/material/styles';
|
||||||
import { Avatar, BonusPoints, StatRow } from '@global-components';
|
import { Avatar } from './battle-dialog/Avatar';
|
||||||
|
import { BonusPoints } from './battle-dialog/BonusPoints';
|
||||||
|
import { StatRow } from './battle-dialog/StatRow';
|
||||||
|
|
||||||
const darkTheme = createTheme({ palette: { mode: 'dark' } });
|
const darkTheme = createTheme({ palette: { mode: 'dark' } });
|
||||||
|
|
||||||
@@ -69,11 +71,11 @@ export const BattleDialog = ({ games }) => {
|
|||||||
const endReason = resign
|
const endReason = resign
|
||||||
? `${resign.charAt(0).toUpperCase() + resign.slice(1)} resigned`
|
? `${resign.charAt(0).toUpperCase() + resign.slice(1)} resigned`
|
||||||
: 26 <= maxPoints ? 'Points' : 'Abandoned';
|
: 26 <= maxPoints ? 'Points' : 'Abandoned';
|
||||||
const canShare = !canContinue;
|
|
||||||
const bothRegistered = game.bothRegistered;
|
const bothRegistered = game.bothRegistered;
|
||||||
const canContinue = bothRegistered && !resign && 26 > maxPoints;
|
|
||||||
const playUrl = `${window.location.origin}/play/${game.uuid}`;
|
|
||||||
const shareUrl = `${window.location.origin}/battle/${game.uuid}`;
|
const shareUrl = `${window.location.origin}/battle/${game.uuid}`;
|
||||||
|
const canContinue = bothRegistered && !resign && 26 > maxPoints;
|
||||||
|
const canShare = !canContinue;
|
||||||
|
const playUrl = `${window.location.origin}/play/${game.uuid}`;
|
||||||
|
|
||||||
const duration = formatDuration(game.created, game.date);
|
const duration = formatDuration(game.created, game.date);
|
||||||
const pointDiff = Math.abs((game.redPoints ?? 0) - (game.bluePoints ?? 0));
|
const pointDiff = Math.abs((game.redPoints ?? 0) - (game.bluePoints ?? 0));
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ services:
|
|||||||
App\Service\BattleCardGenerator:
|
App\Service\BattleCardGenerator:
|
||||||
arguments:
|
arguments:
|
||||||
$cacheDir: '%kernel.project_dir%/var/og-cache'
|
$cacheDir: '%kernel.project_dir%/var/og-cache'
|
||||||
|
$fontPath: '%kernel.project_dir%/assets/fonts/Carlito-Bold.ttf'
|
||||||
$minioMediaStorage: '@mineseeker.media.storage'
|
$minioMediaStorage: '@mineseeker.media.storage'
|
||||||
|
|
||||||
Aws\S3\S3Client:
|
Aws\S3\S3Client:
|
||||||
|
|||||||
47
docs/FONTS.md
Normal file
47
docs/FONTS.md
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
# Font Files
|
||||||
|
|
||||||
|
This directory contains TrueType Font (TTF) files used for server-side image generation with PHP GD.
|
||||||
|
|
||||||
|
## Carlito-Bold.ttf
|
||||||
|
|
||||||
|
- **Font:** Carlito Bold
|
||||||
|
- **Source:** Google Fonts (Carlito Project)
|
||||||
|
- **License:** SIL Open Font License 1.1
|
||||||
|
- **URL:** https://github.com/googlefonts/carlito
|
||||||
|
- **Usage:** Used by `BattleCardGenerator` service for generating battle card OG images
|
||||||
|
- **Note:** Carlito is a metric-compatible font family to Calibri
|
||||||
|
|
||||||
|
## Why TTF instead of @fontsource?
|
||||||
|
|
||||||
|
The `@fontsource` npm packages provide WOFF/WOFF2 files for web usage, but PHP's GD library (`imagettftext()`) requires TrueType Font (TTF) files for server-side text rendering.
|
||||||
|
|
||||||
|
## Alternatives
|
||||||
|
|
||||||
|
If you want to use a different font:
|
||||||
|
|
||||||
|
1. **Install system fonts:**
|
||||||
|
```bash
|
||||||
|
# Find available TTF fonts
|
||||||
|
find /usr/share/fonts -name "*.ttf" -type f
|
||||||
|
|
||||||
|
# Copy desired font
|
||||||
|
cp /usr/share/fonts/path/to/Font-Bold.ttf assets/fonts/
|
||||||
|
```
|
||||||
|
|
||||||
|
2. **Download from Google Fonts:**
|
||||||
|
```bash
|
||||||
|
# Visit https://fonts.google.com
|
||||||
|
# Download the font family
|
||||||
|
# Extract the TTF file from the zip
|
||||||
|
```
|
||||||
|
|
||||||
|
3. **Update service configuration:**
|
||||||
|
Edit `config/services.yaml` and update the `$fontPath` parameter.
|
||||||
|
|
||||||
|
## Cache Clearing
|
||||||
|
|
||||||
|
After changing fonts, clear the OG image cache:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
rm -rf var/og-cache/*
|
||||||
|
```
|
||||||
@@ -34,11 +34,11 @@ final class BattleCardGenerator
|
|||||||
{
|
{
|
||||||
private const int WIDTH = 1200;
|
private const int WIDTH = 1200;
|
||||||
private const int HEIGHT = 630;
|
private const int HEIGHT = 630;
|
||||||
private const string FONT = '/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf';
|
|
||||||
private const int AVATAR_SIZE = 120;
|
private const int AVATAR_SIZE = 120;
|
||||||
|
|
||||||
public function __construct(
|
public function __construct(
|
||||||
private readonly string $cacheDir,
|
private readonly string $cacheDir,
|
||||||
|
private readonly string $fontPath,
|
||||||
private readonly FilesystemOperator $minioMediaStorage,
|
private readonly FilesystemOperator $minioMediaStorage,
|
||||||
private readonly LoggerInterface $logger,
|
private readonly LoggerInterface $logger,
|
||||||
) {
|
) {
|
||||||
@@ -159,7 +159,7 @@ final class BattleCardGenerator
|
|||||||
$redBonusPoints = $game->redBonusPoints ?? 0;
|
$redBonusPoints = $game->redBonusPoints ?? 0;
|
||||||
$blueBonusPoints = $game->blueBonusPoints ?? 0;
|
$blueBonusPoints = $game->blueBonusPoints ?? 0;
|
||||||
$bonusText = number_format((float)$redBonusPoints, 1, '.', '') . ' * : * ' . number_format((float)$blueBonusPoints, 1, '.', '');
|
$bonusText = number_format((float)$redBonusPoints, 1, '.', '') . ' * : * ' . number_format((float)$blueBonusPoints, 1, '.', '');
|
||||||
$this->centeredText($im, $bonusText, 24, self::WIDTH / 2, 425, $gold);
|
$this->centeredText($im, $bonusText, 24, self::WIDTH / 2, 445, $gold);
|
||||||
|
|
||||||
if ($winner === 'red') {
|
if ($winner === 'red') {
|
||||||
$resultText = $redName . ' wins';
|
$resultText = $redName . ' wins';
|
||||||
@@ -176,11 +176,11 @@ final class BattleCardGenerator
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ($resultText !== '') {
|
if ($resultText !== '') {
|
||||||
$this->centeredText($im, $resultText, 30, self::WIDTH / 2, 475, $resultColor);
|
$this->centeredText($im, $resultText, 30, self::WIDTH / 2, 495, $resultColor);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($resign) {
|
if ($resign) {
|
||||||
$this->centeredText($im, ucfirst($resign) . ' resigned', 18, self::WIDTH / 2, 508, $muted);
|
$this->centeredText($im, ucfirst($resign) . ' resigned', 18, self::WIDTH / 2, 528, $muted);
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->centeredText($im, 'mineseeker.hu', 16, self::WIDTH / 2, self::HEIGHT - 20, $muted);
|
$this->centeredText($im, 'mineseeker.hu', 16, self::WIDTH / 2, self::HEIGHT - 20, $muted);
|
||||||
@@ -273,23 +273,23 @@ final class BattleCardGenerator
|
|||||||
/** Draw initials */
|
/** Draw initials */
|
||||||
$initials = mb_strtoupper(mb_substr($name, 0, 2));
|
$initials = mb_strtoupper(mb_substr($name, 0, 2));
|
||||||
$fontSize = 48;
|
$fontSize = 48;
|
||||||
$bbox = imagettfbbox($fontSize, 0, self::FONT, $initials);
|
$bbox = imagettfbbox($fontSize, 0, $this->fontPath, $initials);
|
||||||
$textW = $bbox[2] - $bbox[0];
|
$textW = $bbox[2] - $bbox[0];
|
||||||
$textH = $bbox[1] - $bbox[7];
|
$textH = $bbox[1] - $bbox[7];
|
||||||
$textX = $cx - $textW / 2;
|
$textX = $cx - $textW / 2;
|
||||||
$textY = $cy + $textH / 2;
|
$textY = $cy + $textH / 2;
|
||||||
|
|
||||||
$white = imagecolorallocate($im, 255, 255, 255);
|
$white = imagecolorallocate($im, 255, 255, 255);
|
||||||
imagettftext($im, $fontSize, 0, (int)$textX, (int)$textY, $white, self::FONT, $initials);
|
imagettftext($im, $fontSize, 0, (int)$textX, (int)$textY, $white, $this->fontPath, $initials);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Render text centered on $cx. */
|
/** Render text centered on $cx. */
|
||||||
private function centeredText(GdImage $im, string $text, int $size, int $cx, int $y, int $color): void
|
private function centeredText(GdImage $im, string $text, int $size, int $cx, int $y, int $color): void
|
||||||
{
|
{
|
||||||
$bbox = imagettfbbox($size, 0, self::FONT, $text);
|
$bbox = imagettfbbox($size, 0, $this->fontPath, $text);
|
||||||
$w = $bbox[2] - $bbox[0];
|
$w = $bbox[2] - $bbox[0];
|
||||||
imagettftext($im, $size, 0, (int)($cx - $w / 2), $y, $color, self::FONT, $text);
|
imagettftext($im, $size, 0, (int)($cx - $w / 2), $y, $color, $this->fontPath, $text);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Render text centered on $cx, shrinking font size to fit $maxWidth. */
|
/** Render text centered on $cx, shrinking font size to fit $maxWidth. */
|
||||||
@@ -302,7 +302,7 @@ final class BattleCardGenerator
|
|||||||
int $color,
|
int $color,
|
||||||
int $maxWidth
|
int $maxWidth
|
||||||
): void {
|
): void {
|
||||||
$bbox = imagettfbbox($size, 0, self::FONT, $text);
|
$bbox = imagettfbbox($size, 0, $this->fontPath, $text);
|
||||||
$w = $bbox[2] - $bbox[0];
|
$w = $bbox[2] - $bbox[0];
|
||||||
if ($w > $maxWidth) {
|
if ($w > $maxWidth) {
|
||||||
$size = (int)($size * $maxWidth / $w);
|
$size = (int)($size * $maxWidth / $w);
|
||||||
|
|||||||
Reference in New Issue
Block a user