Files
portal/app/tests/Unit/Advertising/BannerGeneratorTest.php
T
Дмитрий ec8f189b07 feat(реклама): Часть 3a — ядро генерации баннеров из одной картинки (GD)
Часть 3a из 6. Чистое ядро под медийные баннеры, без БД/сети.

- BannerSizes: 15 базовых размеров блоков медийной Яндекса (1×).
- BannerGenerator::coverJpeg — GD cover-crop (масштаб+центр-обрезка) в ТОЧНЫЙ
  размер, JPEG с подбором качества под вес ≤512КБ; исключение на нечитаемой картинке.
  Логика повторяет ручной gen_banners.py (Pillow cover) владельца.

Тесты: 5/5 зелёные (квадрат/широкий/высокий, точные пиксели, вес, ошибка).
Дальше 3b: загрузка 1 картинки → все размеры → превью-галерея → утверждение.
Spec: docs/superpowers/specs/2026-07-25-yandex-reklama-medijnaya-pokazy-design.md §4

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-26 11:16:00 +03:00

45 lines
1.6 KiB
PHP

<?php
declare(strict_types=1);
use App\Services\Advertising\BannerGenerator;
/** Хелпер: исходная JPEG-картинка заданного размера (сплошной цвет) как бинарь. */
function srcJpeg(int $w, int $h): string
{
$img = imagecreatetruecolor($w, $h);
imagefill($img, 0, 0, imagecolorallocate($img, 15, 110, 86));
ob_start();
imagejpeg($img, null, 90);
$bin = (string) ob_get_clean();
imagedestroy($img);
return $bin;
}
it('делает JPEG ТОЧНОГО целевого размера из большой квадратной исходной', function () {
$out = (new BannerGenerator())->coverJpeg(srcJpeg(2000, 2000), 300, 250);
$info = getimagesizefromstring($out);
expect($info)->not->toBeFalse()
->and($info[0])->toBe(300)
->and($info[1])->toBe(250)
->and($info['mime'])->toBe('image/jpeg')
->and(strlen($out))->toBeLessThanOrEqual(512000);
});
it('работает для широкого и высокого форматов (cover, точные пиксели)', function () {
$gen = new BannerGenerator();
$wide = getimagesizefromstring($gen->coverJpeg(srcJpeg(1200, 1200), 728, 90));
expect($wide[0])->toBe(728)->and($wide[1])->toBe(90);
$tall = getimagesizefromstring($gen->coverJpeg(srcJpeg(1200, 1200), 240, 600));
expect($tall[0])->toBe(240)->and($tall[1])->toBe(600);
});
it('бросает исключение на нечитаемой картинке', function () {
expect(fn () => (new BannerGenerator())->coverJpeg('не картинка', 300, 250))
->toThrow(RuntimeException::class);
});