使用C将ppm文件从P3转换为P6
我试图编写一个程序,用C语言将p3 PPM文件转换为P6。但我遇到了两个问题。1,我的代码中有一个分段错误。第二,头文件未正确读入转换后的p6文件。这是我的头文件使用C将ppm文件从P3转换为P6,c,pointers,segmentation-fault,ppm,C,Pointers,Segmentation Fault,Ppm,我试图编写一个程序,用C语言将p3 PPM文件转换为P6。但我遇到了两个问题。1,我的代码中有一个分段错误。第二,头文件未正确读入转换后的p6文件。这是我的头文件 #ifndef PPM_UTILS #define PPM_UTILS #include "stdio.h" #include "stdlib.h" #include "string.h" // First meaningful line of the PPM file typedef struct header { ch
#ifndef PPM_UTILS
#define PPM_UTILS
#include "stdio.h"
#include "stdlib.h"
#include "string.h"
// First meaningful line of the PPM file
typedef struct header {
char MAGIC_NUMBER[3];
unsigned int HEIGHT, WIDTH, MAX_COLOR;
} header_t;
// Represents an RGB pixel with integer values between 0-255
typedef struct pixel {
unsigned int R, G, B;
} pixel_t;
// PPM Image representation
typedef struct image {
header_t header;
pixel_t* pixels;
} image_t;
header_t read_header(FILE* image_file);
image_t* read_ppm(FILE* image_file);
image_t* read_p6(FILE* image_file, header_t header);
image_t* read_p3(FILE* image_file, header_t header);
void write_header(FILE* out_file, header_t header);
void write_p6(FILE* out_file, image_t* image);
void write_p3(FILE* out_file, image_t* image);
#endif
我把代码的主要部分分为两个文件,在编译器中合并
#include <stdio.h>
#include "ppm_utils.h"
header_t read_header(FILE* image_file)
{
header_t header;
fscanf(image_file, "%c %d %d %d",header.MAGIC_NUMBER, &header.WIDTH, &header.HEIGHT, &header.MAX_COLOR);
return header;
}
void write_header(FILE* out_file, header_t header)
{
fprintf(out_file, "%c %d %d %d", *header.MAGIC_NUMBER,header.HEIGHT,header.WIDTH,header.MAX_COLOR);
}
image_t* read_ppm(FILE* image_file)
{
header_t header = read_header(image_file);
image_t* image = NULL;
if (strcmp("P3", header.MAGIC_NUMBER) == 0)
{
image = read_p3(image_file, header);
}
else if (strcmp("P6", header.MAGIC_NUMBER) == 0)
{
image = read_p6(image_file, header);
}
return image;
}
image_t* read_p6(FILE* image_file, header_t header)
{
int size;
size = header.HEIGHT * header.WIDTH;
image_t* image = (image_t*) malloc (sizeof(image_t));
image -> header = header;
image -> pixels = (pixel_t*) malloc (sizeof(pixel_t)* size);
char r,g,b;
r = 0;
g = 0;
b = 0;
int i;
for (i=0;i<size;i++){
fscanf(image_file, "%c%c%c", &r, &g, &b);
image -> pixels -> R = (int) r;
image -> pixels -> G = (int) g;
image -> pixels -> B = (int) b;
}
return image;
}
image_t* read_p3(FILE* image_file, header_t header)
{
int size;
size = header.HEIGHT * header.WIDTH;
image_t* image = (image_t*) malloc (sizeof(image_t));
image -> header = header;
image -> pixels = (pixel_t*) malloc (sizeof(pixel_t)* size);
int r,g,b;
r = 0;
g = 0;
b = 0;
int i;
for (i=0;i<size;i++){
fscanf(image_file, "%d %d %d ", &r, &g, &b);
image -> pixels -> R = (int) r;
image -> pixels -> G = (int) g;
image -> pixels -> B = (int) b;
}
return image;
}
void write_p6(FILE* out_file, image_t* image)
{
header_t header = image -> header;
header.MAGIC_NUMBER[1]=6;
write_header(out_file, header);
int size = header.HEIGHT * header.WIDTH;
int i;
for (i=0;i<size;i++){
fprintf(out_file,"%c%c%c", (char) image->pixels->R, (char) image->pixels->G, (char) image->pixels->B);
}
}
void write_p3(FILE* out_file, image_t* image)
{
header_t header = image -> header;
header.MAGIC_NUMBER[1]=3;
write_header(out_file, header);
int size = header.HEIGHT * header.WIDTH;
int i;
for (i=0;i<size;i++){
fprintf(out_file,"%d %d %d ",image->pixels->R,image->pixels->G,image->pixels->B);
}
}
#包括
#包括“ppm_utils.h”
头\u t读取头(文件*图像\u文件)
{
标题(t)标题;;
fscanf(图像文件,“%c%d%d%d”、header.MAGIC\u编号、header.WIDTH、header.HEIGHT和header.MAX\u颜色);
返回头;
}
无效写入头(文件*输出头文件,头文件)
{
fprintf(输出文件,“%c%d%d%d”,*页眉.幻数,页眉.高度,页眉.宽度,页眉.最大颜色);
}
图像*读取ppm(文件*图像文件)
{
header\u t header=读取头(图像文件);
image_t*image=NULL;
if(strcmp(“P3”,标题幻数)==0)
{
图像=读取p3(图像文件,标题);
}
else if(strcmp(“P6”,标题幻数)==0)
{
image=read_p6(图像文件,标题);
}
返回图像;
}
图像\u t*读取\u p6(文件*图像\u文件,头\u t头)
{
整数大小;
尺寸=收割台高度*收割台宽度;
image_t*image=(image_t*)malloc(sizeof(image_t));
图像->标题=标题;
图像->像素=(像素*t*)malloc(大小f(像素*t)*大小);
字符r,g,b;
r=0;
g=0;
b=0;
int i;
对于(i=0;i像素->R=(int)R;
图像->像素->G=(int)G;
图像->像素->B=(int)B;
}
返回图像;
}
图像\u t*读取\u p3(文件*图像\u文件,头\u t头)
{
整数大小;
尺寸=收割台高度*收割台宽度;
image_t*image=(image_t*)malloc(sizeof(image_t));
图像->标题=标题;
图像->像素=(像素*t*)malloc(大小f(像素*t)*大小);
int r,g,b;
r=0;
g=0;
b=0;
int i;
对于(i=0;i像素->R=(int)R;
图像->像素->G=(int)G;
图像->像素->B=(int)B;
}
返回图像;
}
无效写入p6(文件*输出文件,图像*图像)
{
页眉\u t页眉=图像->页眉;
header.MAGIC_编号[1]=6;
写入_头(out_文件,头);
int size=header.HEIGHT*header.WIDTH;
int i;
对于(i=0;i像素->R,(字符)图像->像素->G,(字符)图像->像素->B);
}
}
无效写入p3(文件*输出文件,图像*图像)
{
页眉\u t页眉=图像->页眉;
header.MAGIC_编号[1]=3;
写入_头(out_文件,头);
int size=header.HEIGHT*header.WIDTH;
int i;
对于(i=0;i像素->R,图像->像素->G,图像->像素->B);
}
}
#包括
#包括“ppm_utils.h”
int main(int argc,char*argv[])
{
如果(argc!=3)
{
printf(“程序需要两个参数”);
返回1;
}
文件*fr;
fr=fopen(argv[1],“r”);
如果(fr==NULL)
{
printf(“开户失败”);
}
文件*fw;
fw=fopen(argv[2],“w”);
如果(fw==NULL)
{
printf(“开户失败”);
}
图像=读取ppm(fr);
写入p6(fw,图像);
免费(图像);
自由(图像->像素);
fclose(fr);
fclose(fw);
返回0;
}
你们有什么解决办法吗?在读取标题时,需要指定要读取的幻数的字符数:
fscanf(image_file, "%2c %d %d %d",header.MAGIC_NUMBER, &header.WIDTH, &header.HEIGHT, &header.MAX_COLOR);
要与strcmp()一起使用,数组中的最后一个字节必须设置为0:
header.MAGIC_NUMBER[2] = 0;
写入标题时,需要将其作为字符串写入:
fprintf(out_file, "%s %d %d %d", header.MAGIC_NUMBER,header.HEIGHT,header.WIDTH,header.MAX_COLOR);
for(i=0;i像素->R=(int)R;
图像->像素->G=(int)G;
图像->像素->B=(int)B;
}
使用
fscanf()
,以解析PPM格式头的方式重复分配相同的内存,这是行不通的
正如我在本文第一点中所解释的,PPM头可能包含注释
请注意,此答案同样适用于所有PNM格式,P1至P6(分别为PBM、PGM、PPM、PBM、PGM、PPM和PAM)。它们的标题格式相同,但标题中列出的非负整数值的数量除外(PBM为2,PGM和PPM为3,PAM为4)
(P7,Portable AnyMap或PAM,有一个额外的参数tupletype,它是一个大写字符串。虽然它是一种非常好的通用图像格式,但它的实现频率低于其他参数。如果您自己为tupletype添加解析,下面的方法也适用于它。)
似乎许多人在构造“读取一个PNM格式头值”时遇到了困难我见过太多的例子,这些例子适用于一些但不是所有的PNM格式文件,损害了不可操作性,给开发人员和用户带来了不必要的麻烦,所以我认为有必要用一个例子来说明如何正确地处理这些问题
读取任何PNM格式的头的正确操作很简单:使用fgetc()
读取头的固定部分(p
、格式数字和以下空白字符,'\t'
、'\n'
、'\v'
、'\f'
、'\r'
、或'/code>之一),以及一个帮助函数来解析非负整数值。(对于P1和P4格式,只有两个值,以像素为单位的宽度和高度,按顺序排列;对于P2、P3、P5和P6格式,有三个值:宽度、高度和maxval,其中maxval是文件中使用的最大组件值。)
如果你真的关心学习,我建议你去阅读上面链接到的I中的伪代码,并尝试首先实现自己的伪代码。如果你陷入困境,你可以与下面已知的工作版本进行比较
为简单起见,让我们使用一个辅助函数,pnm\u is\u whitespace(character)
,如果character
是以下空白字符之一,则该函数返回true(非零):
#include <stdlib.h>
#include <stdio.h>
static inline int pnm_is_whitespace(const int c)
{
return (c == '\t' || c == '\n' || c == '\v' ||
c == '\f' || c == '\r' || c == ' ');
}
上述函数解析输入的方式与%d
在scanf()
函数系列e中的解析方式非常相似
for (i=0;i<size;i++){
fscanf(image_file, "%c%c%c", &r, &g, &b);
image -> pixels -> R = (int) r;
image -> pixels -> G = (int) g;
image -> pixels -> B = (int) b;
}
#include <stdlib.h>
#include <stdio.h>
static inline int pnm_is_whitespace(const int c)
{
return (c == '\t' || c == '\n' || c == '\v' ||
c == '\f' || c == '\r' || c == ' ');
}
static inline int pnm_header_value(FILE *src)
{
int c;
/* Skip leading whitespace and comments. */
c = fgetc(src);
while (1) {
if (c == EOF) {
/* File/stream ends before the value. */
return -1;
} else
if (c == '#') {
/* Comment. Skip the rest of the line. */
do {
c = fgetc(src);
} while (c != EOF && c != '\r' && c != '\n');
} else
if (pnm_is_whitespace(c)) {
/* Skip whitespace. */
c = fgetc(src);
} else
break;
}
/* Parse the nonnegative integer decimal number. */
if (c >= '0' && c <= '9') {
int result = (c - '0');
c = fgetc(src);
while (c >= '0' && c <= '9') {
const int old = result;
/* Add digit to number. */
result = 10*result + (c - '0');
/* Overflow? */
if (result < old)
return -1;
/* Next digit. */
c = fgetc(src);
}
/* Do not consume the separator. */
if (c != EOF)
ungetc(c, src);
/* Success. */
return result;
}
/* Invalid character. */
return -1;
}
enum {
PNM_P1 = 1, /* ASCII PBM */
PNM_P2 = 2, /* ASCII PGM */
PNM_P3 = 3, /* ASCII PPM */
PNM_P4 = 4, /* BINARY PBM */
PNM_P5 = 5, /* BINARY PGM */
PNM_P6 = 6, /* BINARY PPM */
PNM_UNKNOWN = 0
};
static inline int pnm_header(FILE *src,
int *width,
int *height,
int *maxdepth)
{
int format = PNM_UNKNOWN;
int value;
if (!src)
return PNM_UNKNOWN;
/* The image always begins with a 'P'. */
if (fgetc(src) != 'P')
return PNM_UNKNOWN;
/* The next character determines the format. */
switch (fgetc(src)) {
case '1': format = PNM_P1; break;
case '2': format = PNM_P2; break;
case '3': format = PNM_P3; break;
case '4': format = PNM_P4; break;
case '5': format = PNM_P5; break;
case '6': format = PNM_P6; break;
default:
errno = 0;
return PNM_UNKNOWN;
}
/* The next character must be a whitespace. */
if (!pnm_is_whitespace(fgetc(src)))
return PNM_UNKNOWN;
/* Next item is the width as a decimal string. */
value = pnm_header_value(src);
if (value < 1)
return PNM_UNKNOWN;
if (width)
*width = value;
/* Next item is the height as a decimal string. */
value = pnm_header_value(src);
if (value < 1)
return PNM_UNKNOWN;
if (height)
*height = value;
/* Maxdepth, for all but P1 and P4 formats. */
if (format == PNM_P1 || format == PNM_P4) {
if (maxdepth)
*maxdepth = 1;
} else {
value = pnm_header_value(src);
if (value < 1)
return PNM_UNKNOWN;
if (maxdepth)
*maxdepth = value;
}
/* The final character in the header must be a whitespace. */
if (!pnm_is_whitespace(fgetc(src)))
return PNM_UNKNOWN;
/* Success. */
return format;
}