diff --git a/src/apps/common/ppm_writer.cpp b/src/apps/common/ppm_writer.cpp
index 368de8bf6..6f0bbbe9e 100644
--- a/src/apps/common/ppm_writer.cpp
+++ b/src/apps/common/ppm_writer.cpp
@@ -10,6 +10,7 @@
 #include <errno.h>
 #include <fstream>
 #include <iostream>
+#include <vector>
 
 #include <libcamera/formats.h>
 #include <libcamera/pixel_format.h>
@@ -20,9 +21,34 @@ int PPMWriter::write(const char *filename,
 		     const StreamConfiguration &config,
 		     const Span<uint8_t> &data)
 {
-	if (config.pixelFormat != formats::BGR888) {
-		std::cerr << "Only BGR888 output pixel format is supported ("
-			  << config.pixelFormat << " requested)" << std::endl;
+	struct FormatTransformation {
+		unsigned int rPos;
+		unsigned int gPos;
+		unsigned int bPos;
+		unsigned int bytesPerPixel;
+	};
+
+	static const std::map<libcamera::PixelFormat, FormatTransformation> transforms = {
+		{ libcamera::formats::R8, { 0, 0, 0, 1 } },
+		{ libcamera::formats::RGB888, { 2, 1, 0, 3 } },
+		{ libcamera::formats::BGR888, { 0, 1, 2, 3 } },
+		{ libcamera::formats::ARGB8888, { 2, 1, 0, 4 } },
+		{ libcamera::formats::XRGB8888, { 2, 1, 0, 4 } },
+		{ libcamera::formats::ABGR8888, { 0, 1, 2, 4 } },
+		{ libcamera::formats::XBGR8888, { 0, 1, 2, 4 } },
+		{ libcamera::formats::RGBA8888, { 3, 2, 1, 4 } },
+		{ libcamera::formats::RGBX8888, { 3, 2, 1, 4 } },
+		{ libcamera::formats::BGRA8888, { 1, 2, 3, 4 } },
+		{ libcamera::formats::BGRX8888, { 1, 2, 3, 4 } },
+	};
+
+	FormatTransformation transformation;
+	if (auto search = transforms.find(config.pixelFormat); search != transforms.end()) {
+		transformation = search->second;
+	} else {
+		std::cerr
+			<< "Only RGB output pixel formats are supported ("
+			<< config.pixelFormat << " requested)" << std::endl;
 		return -EINVAL;
 	}
 
@@ -42,8 +68,22 @@ int PPMWriter::write(const char *filename,
 
 	const unsigned int rowLength = config.size.width * 3;
 	const char *row = reinterpret_cast<const char *>(data.data());
+	const bool transform = config.pixelFormat != formats::BGR888;
+	std::vector<char> transformedRow(transform ? rowLength : 0);
+
 	for (unsigned int y = 0; y < config.size.height; y++, row += config.stride) {
-		output.write(row, rowLength);
+		if (transform) {
+			for (unsigned int x = 0; x < config.size.width; x++) {
+				transformedRow[x * 3] =
+					row[x * transformation.bytesPerPixel + transformation.rPos];
+				transformedRow[x * 3 + 1] =
+					row[x * transformation.bytesPerPixel + transformation.gPos];
+				transformedRow[x * 3 + 2] =
+					row[x * transformation.bytesPerPixel + transformation.bPos];
+			}
+		}
+
+		output.write(transform ? transformedRow.data() : row, rowLength);
 		if (!output) {
 			std::cerr << "Failed to write image data at row " << y << std::endl;
 			return -EIO;
