C未进入合并2个PPM图像的For Loop



尝试将两个相同类型和大小的PPM图像合并在一起时,我已经完全麻木了。我的代码可以读取、显示和保存PPM图像,但不会进入组合两个图像的for循环。这是组合功能:

struct MFI AddImages (struct MFI AddImgOne, struct MFI AddImgTwo)

{
struct MFI AddImgThree = {'P6', AddImgOne.ImgHeight, AddImgOne.ImgWidth, AddImgOne.MaxInfo, AddImgOne.ImageSize};
int CombineCounter;

if(AddImgOne.ImgWidth != AddImgTwo.ImgWidth || AddImgOne.ImgHeight != AddImgTwo.ImgHeight)
{
printf("They're not the same size you dummy!");
exit(0);
}
AddImgThree.ImageSize = AddImgOne.ImgHeight * AddImgTwo.ImgWidth;

AddImgThree.ImageMemory = malloc(AddImgThree.ImageSize * sizeof(unsigned long long));
if (!AddImgThree.ImageMemory)
{printf("theres no space!n");
exit(0);}     

if (AddImgThree.ImageMemory) 
{
for (CombineCounter = 1; CombineCounter < AddImgOne.ImageSize; CombineCounter++)
{
AddImgThree.RGB[CombineCounter].red = AddImgOne.RGB[CombineCounter].red + AddImgTwo.RGB[CombineCounter].red;
AddImgThree.RGB[CombineCounter].blue = AddImgOne.RGB[CombineCounter].blue + AddImgTwo.RGB[CombineCounter].blue;
AddImgThree.RGB[CombineCounter].green = AddImgOne.RGB[CombineCounter].green + AddImgTwo.RGB[CombineCounter].green;
if (AddImgThree.RGB[CombineCounter].red > 255)
{AddImgThree.RGB[CombineCounter].red = 255;}

if (AddImgThree.RGB[CombineCounter].blue > 255)
{AddImgThree.RGB[CombineCounter].blue = 255;}

if (AddImgThree.RGB[CombineCounter].green > 255)
{AddImgThree.RGB[CombineCounter].green = 255;}
}
}
else
printf ("it's not rightn");

free(AddImgThree.ImageMemory);
return AddImgThree;
}

就上下文而言,这也是我对结构的主要功能:

#include <stdio.h> /*printf, scanf, seekf*/
#include <string.h> /*strstr, strcmp, strcat*/
#include <stdlib.h> /*malloc free command*/

struct MFI {
char Format[3];
int ImgHeight, ImgWidth, MaxInfo, ImageSize;
int *ImageMemory;
struct RGBPixel *RGB;
};
struct RGBPixel {
int red, green, blue;
};
struct MFI Reading (char filename[128]);
struct MFI AddImages (struct MFI AddImgOne, struct MFI AddImgTwo);
void Display (struct MFI D);
void Save(struct MFI S);
int main()
{
struct MFI ImgOne;
struct MFI ImgTwo;
struct MFI ImgThree;
char Image1[128];
char Image2[128];

printf("please enter the name of image 1:");
scanf(" %s", Image1);
fseek(stdin,0,SEEK_END);
printf("please enter the name of image 2:");
scanf(" %s", Image2);
fseek(stdin,0,SEEK_END);
ImgOne = Reading(Image1);
ImgTwo = Reading(Image2);
Display(ImgOne);
Display(ImgTwo);
ImgThree = AddImages(ImgOne, ImgTwo);
Save(ImgThree);
printf("nfile is closedn");
free(ImgOne.ImageMemory);
free(ImgTwo.ImageMemory);
free(ImgThree.ImageMemory);
printf("nimage freedn");
return 0;
}

我的阅读功能:

struct MFI Reading (char filename[128])
{
struct MFI R;
FILE *ImageRead; // file pointer or handle
int p; 
if(strstr(filename, ".ppm") == NULL)
{strcat(filename, ".ppm");}

ImageRead = fopen(filename, "rb");

//check if it exists
if (ImageRead == NULL) {
printf("Nope doesn't existn");
exit(0);}

//get all the image information
fscanf(ImageRead, "%s %d %d %d", R.Format, &R.ImgWidth, &R.ImgHeight, &R.MaxInfo);
//allocate memory for image//
R.ImageMemory = malloc(R.ImgHeight * R.ImgWidth * sizeof(int*));
if (!R.ImageMemory)
{printf("theres no space!n");
exit(0);}
//check if its a PPM
if (!strcmp(R.Format, "P3"))
printf("This is a ppmn");
else
{
if (!strcmp (R.Format, "P2"))
printf("This is a pgmn");
else
{
if (!strcmp (R.Format, "P5"))
printf("This is a pgmn");
else 
{printf("this isn't a ppm file");}
}
}
p = getc(ImageRead);
while (p == '#')
{
while (getc(ImageRead) != 'n')
{
p = getc(ImageRead);
}
}
ungetc(p, ImageRead);
//check image size
if(R.ImgHeight > 1080 || R.ImgWidth > 1920)
{printf ("This is too big!!");}
R.ImageSize = R.ImgWidth*R.ImgHeight;
while (fgetc(ImageRead) != 'n');
R.RGB = malloc(3*R.ImageSize * sizeof(R.RGB));
if (fread(R.RGB, 3*R.ImgHeight, 4*R.ImgWidth-3, ImageRead) != EOF)
printf("error with loading image");
//reading image width and height
printf("The height of the image is %d and the width is %dn", R.ImgWidth, R.ImgHeight);
printf("The maximum value of each pixel is %dn", R.MaxInfo);

return R;
}

还有我的保存功能:

void Save(struct MFI S)
{   FILE *SavePointer;
char InputFileName[128];

printf("nPlease Enter the Name of the file you want to Store this Array In: n");
scanf("%s", InputFileName);
SavePointer = fopen(InputFileName, "r");

if(SavePointer != NULL)
{
printf("File exits, try another name");
fclose(SavePointer);
exit(0);
}
else   
{
fclose(SavePointer);
printf("File is good to go!");
}

if(strstr(InputFileName, ".ppm") == NULL)
{strcat(InputFileName, ".ppm");}
SavePointer = fopen(InputFileName, "wb");
if (!SavePointer)
{
printf ("Lost your File pointer!");
exit (0);
}
fprintf(SavePointer, "%sn%d %dn%dn", S.Format, S.ImgWidth, S.ImgHeight, S.MaxInfo);
fwrite(S.RGB, 3*S.ImgHeight, 4*S.ImgWidth-3, SavePointer);
fclose(SavePointer);
return;
}

编辑

我已经重写了函数的最后一部分,所以现在程序将进入for循环,但在分配数组元素值时将停止。。。

for (CombineCounter = 0; CombineCounter < AddImgOne.ImageSize; CombineCounter++)
{
unsigned int red = AddImgOne.RGB[CombineCounter].red + AddImgTwo.RGB[CombineCounter].red;

if (red > 255)
{red = 255;}
AddImgThree.RGB[CombineCounter].red = red; //exits entire code when here


unsigned int blue = AddImgOne.RGB[CombineCounter].blue + AddImgTwo.RGB[CombineCounter].blue;
if (blue > 255)
{blue = 255;}
AddImgThree.RGB[CombineCounter].blue = blue;

unsigned int green = AddImgOne.RGB[CombineCounter].green + AddImgTwo.RGB[CombineCounter].green;
if (green > 255)
{green = 255;}
AddImgThree.RGB[CombineCounter].green =  green;
}

通过调整剪辑,AddImages非常接近。

但是,代码中的其他地方也存在一些问题。

Reading中,我们需要分配RGB(而不是ImageMemory(。正如我在顶部评论中提到的,ImageMemory是多余的。

我们想要fgetc而不是getc

Reading检查有效格式,但它处理P6[二进制]格式。

P6格式的像素可以大于一个字节[如果MaxInfo是65535而不是255]。但是,Reading试图对像素数据执行单个fread,因此我们只能处理255的情况。

但是,正如我在顶部评论中提到的,这些是字节(即unsigned char(值。因此,RGBPixel的每个元素都需要是unsigned char,并且而不是int

正如您所拥有的(例如(,文件中像素0的RGB值和像素1的R值存储在第一个RGB阵列元素的[4字节]red元素中。

fread返回计数,而不返回EOF

fread调用[和Save]中的fwrite不会传输正确的字节数。

并非所有调用都会检查错误返回。而且,如果他们确实出错了,打印原因会有所帮助(例如strerror(errno)(。

不要在stdin上执行fseek


将CCD_ 27传递到函数";"按值";,更常见的是在"0"附近传递CCD_ 28;"通过指针";。通过值传递时,必须将struct的整个内容推送到堆栈上。并且,如果按值返回struct调用程序必须为堆栈帧中的返回值保留空间。

在当前的情况下,这还不算太糟。但是,它的规模不太好。如果我们有(例如(一个struct,其中有数据,它可能非常慢,并可能导致堆栈溢出:

struct bigstruct {
int x;
int y;
int array[10000000];
};

从风格上讲,保持参数名称和堆栈变量名称较短是一种很好的做法。


这是重构后的代码。我添加了一些注释。在可能的情况下,我用cpp条件句将旧代码与新代码括起来:

#if 0
// old code
#else
// new code
#endif

我还为struct添加了typedef语句。并且,我将函数转换为使用指向结构的指针

尽管我试图保留尽可能多的代码,但我不得不对其进行一些重构。

正如我提到的,AddImages的状态很好,但我对它进行了一些重构,使其更简单,并说明了指向像素的指针的使用。

我用一些P6文件映像测试了它,它似乎可以工作。

所以,这是代码:

#include <stdio.h>                      /* printf, scanf, seekf */
#include <string.h>                     /* strstr, strcmp, strcat */
#include <stdlib.h>                     /* malloc free command */
#include <errno.h>
#include <sys/stat.h>
#define fault(_fmt...) 
do { 
printf(_fmt); 
exit(1); 
} while (0)
typedef struct RGBPixel {
#if 0
int red;
int green;
int blue;
#else
unsigned char red;
unsigned char green;
unsigned char blue;
#endif
} RGBPixel;
typedef struct MFI {
char Format[3];
int ImgHeight;
int ImgWidth;
int MaxInfo;
int ImgSize;
RGBPixel *RGB;
} MFI;
void
Display(MFI *D)
{
}
static inline unsigned char
AddPixel(unsigned int p1,unsigned int p2)
{
unsigned int p3;
// NOTE: to prevent truncation on the right side of the assignment, we're
// using "unsigned int" [instead of "unsigned char"] for the arguments.
//
// as part of the C calling conventions, passing "unsigned char" values are
// "zero extended" to "unsigned int" _even_ if the arg is "unsigned char"
// because [most] stack pushes have to be word aligned
//
// we take advantage of that to eliminate the explicit casting below
#if 0
p3 = (unsigned int) p1 + (unsigned int) p2;
#else
p3 = p1 + p2;
#endif
if (p3 > 255)
p3 = 255;
return p3;
}
void
AddImages(MFI *img3,const MFI *img1,const MFI *img2)
{
int CombineCounter;
const RGBPixel *pix1;
const RGBPixel *pix2;
RGBPixel *pix3;
if (img1->ImgWidth != img2->ImgWidth || img1->ImgHeight != img2->ImgHeight)
fault("They're not the same size you dummy!");
*img3 = *img1;
img3->RGB = malloc(sizeof(*img3->RGB) * img3->ImgSize);
if (img3 == NULL)
fault("no memory for img3 -- %sn",strerror(errno));
pix1 = img1->RGB;
pix2 = img2->RGB;
pix3 = img3->RGB;
for (CombineCounter = 0; CombineCounter < img1->ImgSize;
++CombineCounter, ++pix3, ++pix1, ++pix2) {
pix3->red = AddPixel(pix1->red,pix2->red);
pix3->green = AddPixel(pix1->green,pix2->green);
pix3->blue = AddPixel(pix1->blue,pix2->blue);
}
}
void
P6read(MFI *img,FILE *ImageRead)
{
size_t count;
count = fread(img->RGB,sizeof(*img->RGB),img->ImgSize,ImageRead);
if (count != img->ImgSize)
fault("error with loading image -- %sn",strerror(errno));
}
void
Reading(MFI *img,char *filename)
{
FILE *ImageRead;                    // file pointer or handle
int p;
if (strstr(filename, ".ppm") == NULL) {
strcat(filename, ".ppm");
}
printf("Reading: %s ...n",filename);
ImageRead = fopen(filename, "rb");
// check if it exists
if (ImageRead == NULL)
fault("Nope doesn't existn");
// get all the image information
fscanf(ImageRead, "%s %d %d %d",
img->Format, &img->ImgWidth, &img->ImgHeight, &img->MaxInfo);
img->ImgSize = img->ImgWidth * img->ImgHeight;
// allocate memory for image
img->RGB = malloc(sizeof(*img->RGB) * img->ImgSize);
if (img->RGB == NULL)
fault("theres no space!n");
// skip over comment
#if 0
p = fgetc(ImageRead);
while (p == '#') {
while (fgetc(ImageRead) != 'n') {
p = fgetc(ImageRead);
}
}
ungetc(p, ImageRead);
#else
while (1) {
p = fgetc(ImageRead);
if (p != '#')
break;
while (1) {
if (p == 'n')
break;
if (p == EOF)
break;
p = fgetc(ImageRead);
}
}
if (p != 'n')
fault("image file too shortn");
#endif
// check image size
if (img->ImgHeight > 1080 || img->ImgWidth > 1920)
fault("This is too big -- ImgHeight=%d ImgWidth=%dn",
img->ImgHeight,img->ImgWidth);
// reading image width and height
printf("The height of the image is %d and the width is %dn",
img->ImgWidth, img->ImgHeight);
printf("The maximum value of each pixel is %dn", img->MaxInfo);
switch (img->Format[0]) {
case 'P':
switch (img->Format[1]) {
case '1':
fault("This is a P1n");
break;
case '2':
fault("This is a pgmn");
break;
case '3':
fault("This is a ppm P3n");
break;
case '5':
printf("This is a pgmn");
break;
case '6':
printf("This is a ppm P6n");
if (img->MaxInfo == 255)
P6read(img,ImageRead);
else
fault("Unsupported pixel size -- MaxInfo=%dn",img->MaxInfo);
break;
default:
fault("this isn't a ppm file");
break;
}
break;
default:
fault("this isn't a ppm file");
break;
}
}
void
Save(const MFI *img,char *InputFileName)
{
FILE *SavePointer;
// NOTE/FIX: this must be done _before_ the existence check
#if 1
if (strstr(InputFileName, ".ppm") == NULL)
strcat(InputFileName, ".ppm");
#endif
#if 0
SavePointer = fopen(InputFileName, "r");
if (SavePointer != NULL) {
fclose(SavePointer);
exit(0);
}
else {
fclose(SavePointer);
printf("File is good to go!");
}
#else
struct stat st;
if (stat(InputFileName,&st) >= 0)
fault("File exists, try another name");
printf("File is good to go!");
#endif
// NOTE/BUG: this must be done _before_ the existence check
#if 0
if (strstr(InputFileName, ".ppm") == NULL)
strcat(InputFileName, ".ppm");
#endif
SavePointer = fopen(InputFileName, "wb");
if (!SavePointer)
fault("unable to open output file -- %sn",strerror(errno));
fprintf(SavePointer, "%sn%d %dn%dn",
img->Format, img->ImgWidth, img->ImgHeight, img->MaxInfo);
#if 0
fwrite(S.RGB, 3 * S.ImgHeight, 4 * S.ImgWidth - 3, SavePointer);
#else
size_t count = fwrite(img->RGB,sizeof(*img->RGB),img->ImgSize,SavePointer);
if (count != img->ImgSize)
fault("fault during fwrite -- %sn",strerror(errno));
#endif
fclose(SavePointer);
}
void
getfile(char ***argp,char *file,const char *prompt)
{
char **argv = *argp;
char *cp;
do {
cp = *argv;
if (cp != NULL) {
++argv;
strcpy(file,cp);
printf("%s is %sn",prompt,file);
break;
}
printf("please enter the name of %s:",prompt);
scanf(" %s",file);
} while (0);
*argp = argv;
}
int
main(int argc,char **argv)
{
struct MFI ImgOne;
struct MFI ImgTwo;
struct MFI ImgThree;
char Image1[128];
char Image2[128];
char Image3[128];
--argc;
++argv;
getfile(&argv,Image1,"image 1");
getfile(&argv,Image2,"image 2");
getfile(&argv,Image3,"output");
#if 0
ImgOne = Reading(Image1);
ImgTwo = Reading(Image2);
#else
Reading(&ImgOne,Image1);
Reading(&ImgTwo,Image2);
#endif
#if 0
Display(ImgOne);
Display(ImgTwo);
#endif
#if 0
ImgThree = AddImages(ImgOne, ImgTwo);
#else
AddImages(&ImgThree, &ImgOne, &ImgTwo);
#endif
Save(&ImgThree,Image3);
printf("nfile is closedn");
#if 0
free(ImgOne.ImageMemory);
free(ImgTwo.ImageMemory);
free(ImgThree.ImageMemory);
#else
free(ImgOne.RGB);
free(ImgTwo.RGB);
free(ImgThree.RGB);
#endif
printf("nimage freedn");
return 0;
}

最新更新