You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.25 15:25:32