PPM文件生成图像异常求助(无可识别图形)
PPM简笔树图像生成故障修复
我是编程新手,需要使用RGB基础形状生成PPM格式的简单图像。预期图像为底部三分之一区域的绿色矩形、向上突出的棕色竖矩形,以及棕色矩形顶部的绿色圆形(类似简笔树)。但代码运行后图像混乱,即使仅保留背景也呈现杂乱色彩,附上当前代码,恳请帮助排查问题。
用户提供的原始代码:
#include <fstream> #include <iostream> #include <string> using namespace std; const int HEIGHT = 200; const int WIDTH = 300; struct RGB { unsigned char r, g, b; }; void drawRect(RGB ppmImage[][WIDTH], int rectTop, int rectLeft, int rectHeight, int rectWidth, RGB color); void drawCircle(RGB ppmImage[][WIDTH], int centerX, int centerY, int radius, RGB color); bool writeImagePPM(RGB ppmImage[][WIDTH], const string fileName); int main() { RGB ppmImage[HEIGHT][WIDTH]; for (int row = 0; row < HEIGHT; row++) for (int col = 0; col < WIDTH; col++) ppmImage[row][col] = {0, 0, 255}; drawRect(ppmImage, 106, 0, 67, 300, {0, 0, 255}); drawRect(ppmImage, 130, 145, 60, 10, {139, 69, 19}); int centerX = 145 + 10 / 2; int centerY = 130; int radius = 17; drawCircle(ppmImage, centerX, centerY, radius, {0, 210, 0}); writeImagePPM(ppmImage, "imgGen.ppm"); } void drawRect(RGB ppmImage[][WIDTH], int rectTop, int rectLeft, int rectHeight, int rectWidth, RGB color) { for (int y = rectTop; y < rectTop + rectHeight; y++) for (int x = rectLeft; x < rectLeft + rectWidth; x++) ppmImage[y][x] = color; } void drawCircle(RGB ppmImage[][WIDTH], int centerX, int centerY, int radius, RGB color) { for (int y = max(centerY - radius, 0); y <= min(centerY + radius, HEIGHT - 1); ++y) { for (int x = max(centerX - radius, 0); x <= min(centerX + radius, WIDTH - 1); ++x) { if ((x - centerX) * (x - centerX) + (y - centerY) * (y - centerY) <= radius * radius) { ppmImage[y][x] = color; } } } } bool writeImagePPM(RGB ppmImage[][WIDTH], const string fileName) { ofstream imgFile(fileName); if (!imgFile) { cout << "Error opening file: " << fileName << endl; return false; } imgFile << "P6 " << WIDTH << " " << HEIGHT << " 255 "; for (int row = 0; row < HEIGHT; row++) { for (int col = 0; col < WIDTH; col++) { imgFile << static_cast<int>(ppmImage[row][col].r) << ' '; imgFile << static_cast<int>(ppmImage[row][col].g) << ' '; imgFile << static_cast<int>(ppmImage[row][col].b) << ' '; } imgFile << ' '; } imgFile.close(); return true; }
问题排查与修复方案
1. P6格式写入错误(最关键)
PPM的P6是二进制格式,要求直接写入RGB的字节数据,而不是把每个颜色值转成整数再输出带空格的字符串。原来的写法会把每个字节变成1-3个字符,完全破坏了图像的二进制结构,这就是图像乱码的根本原因。
修复方法:将文件以二进制模式打开,直接写入RGB结构体的内存数据。
2. 底部绿色矩形颜色错误
你要的是底部三分之一的绿色矩形,但代码里用的是{0,0,255}(蓝色),和背景色一样,等于没画。改成{0,255,0}才能看到绿色草地。
3. 棕色树干位置不合理
原来的树干起始位置会导致部分区域接近图像边界,调整为从草地顶部往上计算,让树干刚好立在草地上,避免越界风险。
4. 圆形位置错误
原来的圆心Y坐标刚好在树干顶部,圆形会和树干重叠。把圆心往上移,让圆形在树干顶端上方,符合简笔树的视觉效果。
修正后的完整代码
#include <fstream> #include <iostream> #include <string> #include <algorithm> // 用于max/min函数 using namespace std; const int HEIGHT = 200; const int WIDTH = 300; struct RGB { unsigned char r, g, b; }; void drawRect(RGB ppmImage[][WIDTH], int rectTop, int rectLeft, int rectHeight, int rectWidth, RGB color); void drawCircle(RGB ppmImage[][WIDTH], int centerX, int centerY, int radius, RGB color); bool writeImagePPM(RGB ppmImage[][WIDTH], const string fileName); int main() { RGB ppmImage[HEIGHT][WIDTH]; // 初始化背景为蓝色 for (int row = 0; row < HEIGHT; row++) for (int col = 0; col < WIDTH; col++) ppmImage[row][col] = {0, 0, 255}; // 绘制底部绿色草地(高度67,占底部三分之一) drawRect(ppmImage, HEIGHT - 67, 0, 67, WIDTH, {0, 255, 0}); // 绘制棕色树干:宽度10,高度60,居中放置 int trunkWidth = 10; int trunkHeight = 60; int trunkLeft = (WIDTH - trunkWidth) / 2; int trunkTop = HEIGHT - 67 - trunkHeight; drawRect(ppmImage, trunkTop, trunkLeft, trunkHeight, trunkWidth, {139, 69, 19}); // 绘制顶部绿色圆形:圆心在树干正上方,半径17 int radius = 17; int centerX = trunkLeft + trunkWidth / 2; int centerY = trunkTop - radius; drawCircle(ppmImage, centerX, centerY, radius, {0, 210, 0}); writeImagePPM(ppmImage, "imgGen.ppm"); } void drawRect(RGB ppmImage[][WIDTH], int rectTop, int rectLeft, int rectHeight, int rectWidth, RGB color) { // 确保矩形不超出图像边界 int yStart = max(rectTop, 0); int yEnd = min(rectTop + rectHeight, HEIGHT); int xStart = max(rectLeft, 0); int xEnd = min(rectLeft + rectWidth, WIDTH); for (int y = yStart; y < yEnd; y++) for (int x = xStart; x < xEnd; x++) ppmImage[y][x] = color; } void drawCircle(RGB ppmImage[][WIDTH], int centerX, int centerY, int radius, RGB color) { for (int y = max(centerY - radius, 0); y <= min(centerY + radius, HEIGHT - 1); ++y) { for (int x = max(centerX - radius, 0); x <= min(centerX + radius, WIDTH - 1); ++x) { // 用整数运算避免浮点,优化性能 int dx = x - centerX; int dy = y - centerY; if (dx*dx + dy*dy <= radius*radius) { ppmImage[y][x] = color; } } } } bool writeImagePPM(RGB ppmImage[][WIDTH], const string fileName) { // 以二进制模式打开文件,这是P6格式的关键 ofstream imgFile(fileName, ios::binary); if (!imgFile) { cout << "Error opening file: " << fileName << endl; return false; } // 写入P6格式头,注意换行符要用\n,避免平台差异 imgFile << "P6\n" << WIDTH << " " << HEIGHT << "\n255\n"; // 直接写入整个图像的二进制数据 imgFile.write(reinterpret_cast<const char*>(ppmImage), HEIGHT * WIDTH * sizeof(RGB)); imgFile.close(); return true; }
内容的提问来源于stack exchange,提问作者jacobjacobjacob
相关产品推荐
相关产品推荐

