Stream an image from Symfony controller

When sending an image/file from a Symfony controller you would usually read the file from filesystem.
This you can do by passing the file path to the BinaryFileResponse class and return it in the controller, as described in the docs:

use Symfony\Component\HttpFoundation\BinaryFileResponse;

$file = 'path/to/file.txt';
$response = new BinaryFileResponse($file);Code language: PHP (php)

But in some cases you might want to create an image dynamically and return it directly from the controller without storing it on the filesystem.
So you can create your image with the GD library and directly stream the GDImage object from the symfony controller with the StreamedResponse class.

$image = imagecreatetruecolor($imgWidth, $imgHeight);
// do something with the image
return new StreamedResponse(fn () => imagepng($image), 200, ['Content-Type' => 'image/png']);Code language: PHP (php)

Great that was easy, but not so obvious ;)

Another thing you might wonder is how to add the OpenAPI annotation when streaming images to generate a proper documentation for your endpoints.
Just use MediaType class in the Response annotation and set the format to binary.

responses: [
	new OA\Response(
		response: 200,
		description: "dynamic image",
		content: new OA\MediaType(
			mediaType: 'image/png', 
			schema: new OA\Schema(
				type: 'string',
				format: 'binary'
]Code language: PHP (php)

Then finally you should test the StreamedResponse from the controller.
For this you can not use the normal $client->getResponse() but instead use the getInternalResponse which holds the binary data as string however.
So to test the binary response in your test add this:

$response = static::$client->getInternalResponse();
$image = $response->getContent();
self::assertInstanceOf(GdImage::class, imagecreatefromstring($image));Code language: PHP (php)

This seems to be valid from Symfony 4 upwards.
Before Symfony 4 you could get the binary data from $client->getResponse().