测试结果
直接上代码
-std=c++17,记得编译时指定 C++17,创建文件夹的时候要用。不需要创建文件夹可以去掉。
// *********************************************
// Brief: save image as ppm, pbm, pgm
// Note:
// P1 - PBM_ASCII, P2 - PGM_ASCII, P3 - PPM_ASCII,
// P4 - PBM_BINARY, P5 - PGM_BINARY, P6 - PPM_BINARY
//
// Date: 13 Jul 2025
// *********************************************
#include <vector>
#include <iostream>
#include <filesystem>
static void createPath(const std::string &fullPath)
{
std::filesystem::path filePath(fullPath);
// get filename without extension
std::string filename = filePath.stem().string();
// create new path
std::filesystem::path dirPath = filePath.parent_path();// / filename;
// create folder
if (std::filesystem::exists(dirPath))
{
} else if (std::filesystem::create_directories(dirPath))
{
printf("Create Folder Success: %s\n", dirPath.c_str());
} else
{
printf("Create Folder Failed, might already exists: %s\n", dirPath.c_str());
}
}
/**
* PBM - Portable BitMap, 0 - White, 1 - Black
*
*/
static void saveImgAsPBM(const std::string &dumpPath, uint8_t *data, size_t width, size_t height)
{
// PBM is an image format, can open with default image viewer on ubuntu.
std::string flow_ppm_filename = dumpPath + ".pbm";
createPath(flow_ppm_filename);
FILE *pOutFile = NULL;
pOutFile = fopen(flow_ppm_filename.c_str(), "wb");
fprintf(pOutFile, "P4\n");
fprintf(pOutFile, "%ld %ld\n", (long) width, (long) height);
// fprintf(pOutFile, "1\n"); // no max value for PBM
// packing image data, MSB first
const size_t rowBytes = (width + 7) / 8;
std::vector<uint8_t> packed(rowBytes);
for (size_t y = 0; y < height; ++y)
{
std::fill(packed.begin(), packed.end(), 0); // clear buffer
for (size_t x = 0; x < width; ++x)
{
const size_t byteIdx = x / 8;
const size_t bitPos = 7 - (x % 8); // MSB first
if (data[y * width + x])
{
packed[byteIdx] |= (1 << bitPos);
}
}
// write into file
fwrite(packed.data(), 1, rowBytes, pOutFile);
}
fclose(pOutFile);
}
/**
* PGM - Portable GreyMap, 0 - Black, MaxNum - White
*/
static void saveImgAsPGM(const std::string &dumpPath, uint8_t *data, size_t width, size_t height)
{
// PGM is an image format, can open with default image viewer on ubuntu.
std::string flow_ppm_filename = dumpPath + ".pgm";
createPath(flow_ppm_filename);
FILE *pOutFile = NULL;
pOutFile = fopen(flow_ppm_filename.c_str(), "wb");
fprintf(pOutFile, "P5\n");
fprintf(pOutFile, "%ld %ld\n", (long) width, (long) height);
fprintf(pOutFile, "255\n"); // set max value to 255
fwrite(data, 1, 1 * width * height, pOutFile);
fclose(pOutFile);
}
/**
* PPM - Portable PixMap
*/
static void saveImgAsPPM(const std::string &dumpPath, uint8_t *data, size_t width, size_t height)
{
// PPM is an image format, can open with default image viewer on ubuntu.
std::string flow_ppm_filename = dumpPath + ".ppm";
createPath(flow_ppm_filename);
FILE *pOutFile = NULL;
pOutFile = fopen(flow_ppm_filename.c_str(), "wb");
fprintf(pOutFile, "P6\n");
fprintf(pOutFile, "%ld %ld\n", (long) width, (long) height);
fprintf(pOutFile, "255\n");
fwrite(data, 1, 3 * width * height, pOutFile);
fclose(pOutFile);
}
int main() {
const size_t width = 256;
const size_t height = 256;
const std::string basePath = "./output/test_image";
// 1. PBM test
std::vector<uint8_t> pbmData(width * height, 1);
for (size_t y = 0; y < height; ++y) {
for (size_t x = 0; x < width; ++x) {
pbmData[y * width + x] = (x / 16 + y / 16) % 2; // checkerboard pattern
}
}
saveImgAsPBM(basePath + "_pbm", pbmData.data(), width, height);
std::cout << "PBM Test finished.\n";
// 2. PGM test
std::vector<uint8_t> pgmData(width * height);
for (size_t y = 0; y < height; ++y) {
for (size_t x = 0; x < width; ++x) {
pgmData[y * width + x] = x % 256; // gradient
}
}
saveImgAsPGM(basePath + "_pgm", pgmData.data(), width, height);
std::cout << "PGM Test finished.\n";
// 3. PPM test
std::vector<uint8_t> ppmData(3 * width * height);
for (size_t y = 0; y < height; ++y) {
for (size_t x = 0; x < width; ++x) {
size_t pos = 3 * (y * width + x);
ppmData[pos] = x % 256; // R, gradient value
ppmData[pos + 1] = y % 256; // G, gradient value
ppmData[pos + 2] = 128; // B
}
}
saveImgAsPPM(basePath + "_ppm", ppmData.data(), width, height);
std::cout << "PPM Test finished.\n";
return 0;
}
Refference
- DeepSeek 内容
- Main 函数编写
- PBM Packing 代码实现
- PPM、PGM、PBM三种都是图像文件格式
- PBM Packing 原理