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

如何在C语言生成的PPM文件中叠加多图形制作南瓜图像?

如何在同一PPM文件中叠加多个图形制作南瓜主题图像

我正在开发一款C语言程序,目标是生成带有方形眼睛、鼻子和矩形嘴巴的南瓜主题PPM图像。当前代码可生成橙色圆形,通过修改RGB值可调整图形颜色,修改命令行参数(如./SpookyImageGenerator output.ppm 800 600 100)可切换生成的图形类型(圆、正方形、矩形),但目前只能将不同图形输出到不同PPM文件。请问如何在同一PPM文件中叠加多个图形以完成完整图像制作?


当前主程序代码

#include <stdlib.h>
#include <stdio.h>
#include "MyFunctions.h"

int main(int argc, char *argv[]) {

    int numRows;            // Number of rows in our image.
    int numCols;            // Number of columns in our image.
    int imageSize;          // The total numberof rows * columns in the image
    int Radius;             // The radius of the circle added to image.
    int row, col;           // The marker to know where we are in the image
    int InOrOut;            // Flag for in or outside of the circle

    unsigned char *outImage;     /* Pixel Pointer           */
    unsigned char *ptr;          /* Pointer                 */
    FILE *outputFP;              /* My out put file pointer */

    printf("=======================================\n");
    printf("        This will make an image        \n");
    printf("=======================================\n");

    // Read in some command line arguments.

    if(argc != 5) {
        printf("Usage: ./[1]SpookyImageMaker [2]OutFile [3]numRows [4]numCols [5]Radius \n");
        exit(1);
    }
    if((numRows = atoi(argv[2])) <= 0) {
        printf("The given number rows is not positive!\n");
    }
    if((numCols = atoi(argv[3])) <= 0) {
        printf("The given number of columns is not positive!\n");
    }
    if((Radius = atoi(argv[4])) <= 0) {
        printf("Check your radius -- it should be positive!\n");
    }

    printf("=============================================\n");
    printf("        Now working to set up sizes.         \n");
    printf("=============================================\n");

    imageSize = numRows*numCols*3;
    outImage = (unsigned char *) malloc(imageSize);     

    /* Open the image for writing. */
    if ( (outputFP = fopen(argv[1],"w")) == NULL) {
        perror("output open error");
        printf("Error in opening your given output file!\n");
        exit(2);
    }

    printf("=============================================\n");
    printf("        Index Through the given image.       \n");
    printf("=============================================\n");

    ptr = outImage;

    for( row = 0 ; row < numRows ; row++) {
        for( col = 0 ; col < numCols ; col++){
            printf("Row and Col (%d,%d)\n",row,col);
            InOrOut = CheckRadius(numRows, numCols, Radius, row, col);

            if(InOrOut == 1) {
                *ptr     = 255;    // red pixel
                *(ptr+1) = 117;    // green pixel
                *(ptr+2) = 24;     // blue pixel
            } else {
                *ptr     = 0;    // red pixel
                *(ptr+1) = 0;    // green pixel
                *(ptr+2) = 0;    // blue pixel
            }
            // Advance the pixel pointer
            ptr += 3;
        }
    }

    printf("============================================\n");
    printf("   Write it all out to a file for viewing.  \n");
    printf("============================================\n");

    fprintf(outputFP, "P6 %d %d 255\n", numCols, numRows);
    fwrite(outImage, 1, imageSize, outputFP);

    /* Done */
    fclose(outputFP);
    return 0;
}

HelperFunctions.c 代码

#include <math.h>                

int CheckRadius(int TotRows, int TotCols, int Radius, int CurPixRow, int CurPixCol){

    int InOrOut   = 0;           // Returns 0 or 1 for out and in side the circle respectively.
    int CenterRow = TotRows/2;   // Place holder for the center with regard to rows.
    int CenterCol = TotCols/2;   // Place holder for the center column.
    int dist      = 0;           // Place in memory for the distance between CurPix and Center.

    // printf("I'm in CheckRadius\n");

    // Compute The distance.
    dist = pow((pow(CenterRow-CurPixRow,2.0)+pow(CenterCol-CurPixCol,2.0)),0.5);

    // Check is dist < Radius and set flag.
    if( dist < Radius){
        InOrOut = 1;
    }

    return InOrOut;
}

MyFunctions.h(当前内容)

#ifndef MYFUNCTIONS_H
#define MYFUNCTIONS_H

int CheckRadius(int TotRows, int TotCols, int Radius, int CurPixRow, int CurPixCol);

#endif

实现多图形叠加的步骤

1. 初始化图像为背景色

先将整个图像数组初始化为背景色(比如黑色),后续绘制的图形会直接覆盖对应位置的像素:

// 初始化所有像素为黑色背景
ptr = outImage;
for (row = 0; row < numRows; row++) {
    for (col = 0; col < numCols; col++) {
        *ptr = 0;
        *(ptr+1) = 0;
        *(ptr+2) = 0;
        ptr += 3;
    }
}

2. 绘制底层南瓜(橙色圆形)

遍历像素,只修改圆形范围内的像素为南瓜橙色,保留背景色不变:

ptr = outImage;
for (row = 0; row < numRows; row++) {
    for (col = 0; col < numCols; col++) {
        if (CheckRadius(numRows, numCols, Radius, row, col) == 1) {
            *ptr = 255;    // 红色通道
            *(ptr+1) = 117; // 绿色通道
            *(ptr+2) = 24;  // 蓝色通道
        }
        ptr += 3;
    }
}

3. 添加新的图形判断函数

在HelperFunctions.c中添加方形、矩形的像素判断函数,用于绘制五官:

// 判断像素是否在指定中心和尺寸的方形内(眼睛、鼻子)
int CheckSquare(int centerRow, int centerCol, int size, int curRow, int curCol) {
    int halfSize = size / 2;
    if (curRow >= centerRow - halfSize && curRow <= centerRow + halfSize &&
        curCol >= centerCol - halfSize && curCol <= centerCol + halfSize) {
        return 1;
    }
    return 0;
}

// 判断像素是否在指定中心、宽高的矩形内(嘴巴)
int CheckRectangle(int centerRow, int centerCol, int width, int height, int curRow, int curCol) {
    int halfWidth = width / 2;
    int halfHeight = height / 2;
    if (curRow >= centerRow - halfHeight && curRow <= centerRow + halfHeight &&
        curCol >= centerCol - halfWidth && curCol <= centerCol + halfWidth) {
        return 1;
    }
    return 0;
}

同时更新MyFunctions.h的函数声明:

#ifndef MYFUNCTIONS_H
#define MYFUNCTIONS_H

int CheckRadius(int TotRows, int TotCols, int Radius, int CurPixRow, int CurPixCol);
int CheckSquare(int centerRow, int centerCol, int size, int curRow, int curCol);
int CheckRectangle(int centerRow, int centerCol, int width, int height, int curRow, int curCol);

#endif

4. 叠加绘制五官

在南瓜绘制完成后,再次遍历像素,将五官位置的像素修改为黑色:

ptr = outImage;
int imageCenterRow = numRows / 2;
int imageCenterCol = numCols / 2;

// 五官尺寸与位置参数
int eyeSize = 20;
int eyeOffset = 50; // 眼睛与中心的横向偏移
int noseSize = 15;
int mouthWidth = 80;
int mouthHeight = 30;
int mouthOffset = 40; // 嘴巴与中心的纵向偏移

for (row = 0; row < numRows; row++) {
    for (col = 0; col < numCols; col++) {
        // 左眼
        if (CheckSquare(imageCenterRow - eyeOffset, imageCenterCol - eyeOffset, eyeSize, row, col) == 1) {
            *ptr = 0;
            *(ptr+1) = 0;
            *(ptr+2) = 0;
        }
        // 右眼
        else if (CheckSquare(imageCenterRow - eyeOffset, imageCenterCol + eyeOffset, eyeSize, row, col) == 1) {
            *ptr = 0;
            *(ptr+1) = 0;
            *(ptr+2) = 0;
        }
        // 鼻子
        else if (CheckSquare(imageCenterRow, imageCenterCol, noseSize, row, col) == 1) {
            *ptr = 0;
            *(ptr+1) = 0;
            *(ptr+2) = 0;
        }
        // 嘴巴
        else if (CheckRectangle(imageCenterRow + mouthOffset, imageCenterCol, mouthWidth, mouthHeight, row, col) == 1) {
            *ptr = 0;
            *(ptr+1) = 0;
            *(ptr+2) = 0;
        }
        ptr += 3;
    }
}

5. 优化命令行参数(可选)

可以去掉手动输入半径的参数,改为自动计算南瓜大小:

if(argc != 4) {
    printf("Usage: ./SpookyImageMaker OutFile numRows numCols\n");
    exit(1);
}
numRows = atoi(argv[2]);
numCols = atoi(argv[3]);
// 自动设置南瓜半径为图像较小边的1/3
int Radius = (numRows < numCols) ? numRows/3 : numCols/3;

核心原理

图形叠加的本质是分层覆盖:先绘制底层的南瓜图形,再在上层绘制五官图形。由于直接修改像素数组的数值,后续绘制的像素会覆盖之前的数值,从而实现多个图形在同一文件中的叠加效果。

内容的提问来源于stack exchange,提问作者TheSwampyBogbeard

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.06 21:17:32