convertImage($file); expect($result)->toHaveKeys(['filename', 'thumbnail']); expect($result['filename'])->toStartWith('slides/')->toEndWith('.jpg'); expect($result['thumbnail'])->toStartWith('slides/thumbnails/')->toEndWith('.jpg'); expect(Storage::disk('public')->exists($result['filename']))->toBeTrue(); expect(Storage::disk('public')->exists($result['thumbnail']))->toBeTrue(); $mainPath = Storage::disk('public')->path($result['filename']); [$width, $height] = getimagesize($mainPath); expect($width)->toBe(1920); expect($height)->toBe(1080); $image = imagecreatefromjpeg($mainPath); expect($image)->not->toBeFalse(); $corner = imagecolorsforindex($image, imagecolorat($image, 0, 0)); $center = imagecolorsforindex($image, imagecolorat($image, 960, 540)); expect($corner['red'] + $corner['green'] + $corner['blue'])->toBeLessThan(20); expect($center['red'])->toBeGreaterThan(100); $thumbPath = Storage::disk('public')->path($result['thumbnail']); [$thumbWidth, $thumbHeight] = getimagesize($thumbPath); expect($thumbWidth)->toBe(320); expect($thumbHeight)->toBe(180); }); test('small image is upscaled with at most two black bars', function () { $service = app(FileConversionService::class); // 4:3 image → taller than 16:9 → pillarbox (left/right only) $file = makePngUpload('small.png', 400, 300); $result = $service->convertImage($file); $mainPath = Storage::disk('public')->path($result['filename']); $image = imagecreatefromjpeg($mainPath); expect($image)->not->toBeFalse(); // Left/right edges must be black (pillarbox) $left = imagecolorsforindex($image, imagecolorat($image, 0, 540)); $right = imagecolorsforindex($image, imagecolorat($image, 1919, 540)); expect($left['red'] + $left['green'] + $left['blue'])->toBeLessThan(20); expect($right['red'] + $right['green'] + $right['blue'])->toBeLessThan(20); // Top/bottom center must be image content (red), NOT black $topCenter = imagecolorsforindex($image, imagecolorat($image, 960, 0)); $bottomCenter = imagecolorsforindex($image, imagecolorat($image, 960, 1079)); expect($topCenter['red'])->toBeGreaterThan(100); expect($bottomCenter['red'])->toBeGreaterThan(100); }); test('exact 16:9 image has no black bars', function () { $service = app(FileConversionService::class); $file = makePngUpload('exact.png', 1920, 1080); $result = $service->convertImage($file); $mainPath = Storage::disk('public')->path($result['filename']); $image = imagecreatefromjpeg($mainPath); expect($image)->not->toBeFalse(); // All corners must be image content (red), no black bars $tl = imagecolorsforindex($image, imagecolorat($image, 0, 0)); $tr = imagecolorsforindex($image, imagecolorat($image, 1919, 0)); $bl = imagecolorsforindex($image, imagecolorat($image, 0, 1079)); $br = imagecolorsforindex($image, imagecolorat($image, 1919, 1079)); expect($tl['red'])->toBeGreaterThan(100); expect($tr['red'])->toBeGreaterThan(100); expect($bl['red'])->toBeGreaterThan(100); expect($br['red'])->toBeGreaterThan(100); }); test('small 16:9 image is upscaled without black bars', function () { $service = app(FileConversionService::class); $file = makePngUpload('small169.png', 320, 180); $result = $service->convertImage($file); $mainPath = Storage::disk('public')->path($result['filename']); [$width, $height] = getimagesize($mainPath); expect($width)->toBe(1920); expect($height)->toBe(1080); $image = imagecreatefromjpeg($mainPath); expect($image)->not->toBeFalse(); // All corners must be image content (red), no black bars $tl = imagecolorsforindex($image, imagecolorat($image, 0, 0)); $br = imagecolorsforindex($image, imagecolorat($image, 1919, 1079)); expect($tl['red'])->toBeGreaterThan(100); expect($br['red'])->toBeGreaterThan(100); }); test('portrait image gets pillarbox bars on left and right', function () { $service = app(FileConversionService::class); $file = makePngUpload('portrait.png', 1080, 1920); $result = $service->convertImage($file); $mainPath = Storage::disk('public')->path($result['filename']); [$width, $height] = getimagesize($mainPath); expect($width)->toBe(1920); expect($height)->toBe(1080); $image = imagecreatefromjpeg($mainPath); expect($image)->not->toBeFalse(); $left = imagecolorsforindex($image, imagecolorat($image, 10, 540)); $right = imagecolorsforindex($image, imagecolorat($image, 1910, 540)); $center = imagecolorsforindex($image, imagecolorat($image, 960, 540)); expect($left['red'] + $left['green'] + $left['blue'])->toBeLessThan(20); expect($right['red'] + $right['green'] + $right['blue'])->toBeLessThan(20); expect($center['red'])->toBeGreaterThan(100); }); function makePngUpload(string $name, int $width, int $height): UploadedFile { $path = tempnam(sys_get_temp_dir(), 'cts-img-'); if ($path === false) { throw new RuntimeException('Temp-Datei konnte nicht erstellt werden.'); } $image = imagecreatetruecolor($width, $height); if ($image === false) { throw new RuntimeException('Bild konnte nicht erstellt werden.'); } $red = imagecolorallocate($image, 255, 0, 0); imagefill($image, 0, 0, $red); imagepng($image, $path); return new UploadedFile($path, $name, 'image/png', null, true); }