From patchwork Sun Apr 13 08:21:33 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Pavel Machek X-Patchwork-Id: 23177 Return-Path: X-Original-To: parsemail@patchwork.libcamera.org Delivered-To: parsemail@patchwork.libcamera.org Received: from lancelot.ideasonboard.com (lancelot.ideasonboard.com [92.243.16.209]) by patchwork.libcamera.org (Postfix) with ESMTPS id 495F9C3213 for ; Sun, 13 Apr 2025 08:21:38 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 3CD0968AB3; Sun, 13 Apr 2025 10:21:37 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ucw.cz header.i=@ucw.cz header.b="AOLApKhC"; dkim-atps=neutral Received: from jabberwock.ucw.cz (jabberwock.ucw.cz [46.255.230.98]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 8F10268A38 for ; Sun, 13 Apr 2025 10:21:34 +0200 (CEST) Received: by jabberwock.ucw.cz (Postfix, from userid 1017) id 096D51C013F; Sun, 13 Apr 2025 10:21:34 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ucw.cz; s=gen1; t=1744532494; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type; bh=Aea+8zeXxH2ZujqclUdAlf+wUVo6RGAvrWZGrXVOjx4=; b=AOLApKhC6JAaqMEzteNIh/ilW3hcUTBVYluv9VWhsXbkdleSO5I5JMcqEm4W8romGZTww0 9lYirDGXcdkc5YlVIbGjc9XMXt+WiIQslwKInueIFwtQO4a1vB5MRRbMFKg1YZh5clyfqg vI2SH0fQiMTgGR2Hkm5iNtXDMshxDZA= Date: Sun, 13 Apr 2025 10:21:33 +0200 From: Pavel Machek To: laurent.pinchart@ideasonboard.com, libcamera-devel@lists.libcamera.org Subject: [PATCH] cam: Convert RGB variations to BGR Message-ID: MIME-Version: 1.0 Content-Disposition: inline X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" swIsp with libcamera produces ARGB data by default, which needs conversion during write. Implement it and similar conversions. Signed-off-by: Pavel Machek 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 &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(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(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 rowBuffer(rowLength); + const uint8_t *row = reinterpret_cast(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(pixel[r_pos]); + rowBuffer[x * 3 + 1] = static_cast(pixel[g_pos]); + rowBuffer[x * 3 + 2] = static_cast(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; }