[PATCH] cam: Convert RGB variations to BGR

Pavel Machek pavel at ucw.cz
Sun Apr 13 10:21:33 CEST 2025


swIsp with libcamera produces ARGB data by default, which needs
conversion during write. Implement it and similar conversions.
    
Signed-off-by: Pavel Machek <pavel at ucw.cz>

diff --git a/src/apps/common/ppm_writer.cpp b/src/apps/common/ppm_writer.cpp
index 368de8bf..ddbd3263 100644
--- a/src/apps/common/ppm_writer.cpp
+++ b/src/apps/common/ppm_writer.cpp
@@ -20,8 +20,56 @@ 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 ("
+	int r_pos, g_pos, b_pos, bpp;
+	switch (config.pixelFormat) {
+	case libcamera::formats::R8:
+		r_pos = 0;
+		g_pos = 0;
+		b_pos = 0;
+		bpp = 1;
+		break;
+	case libcamera::formats::RGB888:
+		r_pos = 2;
+		g_pos = 1;
+		b_pos = 0;
+		bpp = 3;
+		break;
+	case libcamera::formats::BGR888:
+		r_pos = 0;
+		g_pos = 1;
+		b_pos = 2;
+		bpp = 3;
+		break;
+	case libcamera::formats::ARGB8888:
+	case libcamera::formats::XRGB8888:
+		r_pos = 2;
+		g_pos = 1;
+		b_pos = 0;
+		bpp = 4;
+		break;
+	case libcamera::formats::RGBA8888:
+	case libcamera::formats::RGBX8888:
+		r_pos = 3;
+		g_pos = 2;
+		b_pos = 1;
+		bpp = 4;
+		break;
+	case libcamera::formats::ABGR8888:
+	case libcamera::formats::XBGR8888:
+		r_pos = 0;
+		g_pos = 1;
+		b_pos = 2;
+		bpp = 4;
+		break;
+	case libcamera::formats::BGRA8888:
+	case libcamera::formats::BGRX8888:
+		r_pos = 1;
+		g_pos = 2;
+		b_pos = 3;
+		bpp = 4;
+		break;
+	default:
+		std::cerr << "Only RGB output pixel formats are supported ("
 			  << config.pixelFormat << " requested)" << std::endl;
 		return -EINVAL;
 	}
@@ -41,14 +89,35 @@ int PPMWriter::write(const char *filename,
 	}
 
 	const unsigned int rowLength = config.size.width * 3;
-	const char *row = reinterpret_cast<const char *>(data.data());
-	for (unsigned int y = 0; y < config.size.height; y++, row += config.stride) {
-		output.write(row, rowLength);
+	// Output without any conversion will be slightly faster
+	if (config.pixelFormat == formats::BGR888) {
+		const char *row = reinterpret_cast<const char *>(data.data());
+		for (unsigned int y = 0; y < config.size.height; y++, row += config.stride) {
+			output.write(row, rowLength);
+			if (!output) {
+				std::cerr << "Failed to write image data at row " << y << std::endl;
+				return -EIO;
+			}
+		}
+		return 0;
+	}
+
+	const unsigned int inputRowBytes = config.stride; // should be >= width * 4
+	// Create a temporary buffer to hold one output row.
+	std::vector<char> rowBuffer(rowLength);
+	const uint8_t *row = reinterpret_cast<const uint8_t *>(data.data());
+	for (unsigned int y = 0; y < config.size.height; y++, row += inputRowBytes) {
+		for (unsigned int x = 0; x < config.size.width; x++) {
+			const uint8_t *pixel = row + x * bpp;
+			rowBuffer[x * 3 + 0] = static_cast<char>(pixel[r_pos]);
+			rowBuffer[x * 3 + 1] = static_cast<char>(pixel[g_pos]);
+			rowBuffer[x * 3 + 2] = static_cast<char>(pixel[b_pos]);
+		}
+		output.write(rowBuffer.data(), rowLength);
 		if (!output) {
 			std::cerr << "Failed to write image data at row " << y << std::endl;
 			return -EIO;
 		}
 	}
-
 	return 0;
 }

-- 
I don't work for Nazis and criminals, and neither should you.
Boycott Putin, Trump, and Musk!
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 195 bytes
Desc: not available
URL: <https://lists.libcamera.org/pipermail/libcamera-devel/attachments/20250413/1ba7a859/attachment.sig>


More information about the libcamera-devel mailing list