我正在尝试编写从P6到P3的转换器,这意味着从以二进制保存的数据到以ASCII保存的数据。
这是我为完成这项工作而编写的函数,但red
,green
和blue
整数获取垃圾值而不是十进制值。
int convertP6toP3(char* fileName)
{
FILE *src, *dest;
char *outputFilename;
char magicNumber[3];
int height, width, depth;
int red = 0, green = 0, blue = 0;
int i, j, widthCounter = 1;
if (checkFileExists(fileName) == FALSE)
{
printf("- Given file does not exists!\n");
return ERROR;
}
else
src = fopen(fileName, "rb");
outputFilename = getOutputFilename(fileName, ".p3.ppm");
dest = fopen(outputFilename, "w+");
// check that the input file is actually in P6 format
fscanf(src, "%s", magicNumber);
if (strcmp(magicNumber, "P6") != 0)
return ERROR;
fscanf(src, "%d %d %d", &height, &width, &depth);
fprintf(dest, "P3\n");
fprintf(dest, "#P3 converted from P6\n");
fprintf(dest, "%d %d\n%d\n", height, width, depth);
for (i = 0; i < width*height; i++)
{
for (j = 0; j < 3; j++)
{
fread(&red, sizeof(int), 1, src);
fread(&green, sizeof(int), 1, src);
fread(&blue, sizeof(int), 1, src);
}
for (j = 0; j < 3; j++)
fprintf(dest, "%d %d %d ", red, green, blue);
if (widthCounter == width)
{
fprintf(dest, "\n");
widthCounter = 1;
}
else
widthCounter++;
}
free(outputFilename);
fclose(src);
fclose(dest);
return TRUE;
}
读取二进制数据我做错了什么?完美阅读高度,宽度和深度。
编辑:在尝试使用读取数据大小后,我得到了一些我无法解释的疯狂结果:
答案 0 :(得分:1)
好的,问题在于恐惧。你正在阅读文件
sizeof(int)
取决于您的编译器,该值可以不同(通常为四个字节)。在P6格式中,每种颜色都存储在一个字节(0 - 255)中。因此,当你正在读取你的值时,你会超出每个像素的范围。
尝试:
fread(&red, sizeof(char), 1, src);
fread(&green, sizeof(char), 1, src);
fread(&blue, sizeof(char), 1, src);
如果需要,可以在以后投射它们。这应该有用。
编辑:您还应该将您的rgb变量视为未签名整理
关于P3 / P6文件格式的一些信息: http://paulbourke.net/dataformats/ppm/
答案 1 :(得分:1)
继续我们在问题的评论主题中的讨论之后,我认为问题在于你阅读二进制数据。
如果每个样本都是一个字节,那么您需要使用unsigned char
作为红色/蓝色/绿色变量,并且我会想fread(&var, 1, 1, src)
。我认为sizeof(int)
可能是4(取决于系统)所以对于红色,绿色和蓝色中的每一个,你一直在读4个无符号字节并将它们存储在有符号整数中......这将导致麻烦。
另外,我认为你不需要你的内循环for(j = ...
我会将你的内循环重写为:
unsigned char red, green blue;
...
for (i = 0; i < width*height; i++)
{
fread(&red, 1, 1, src); //<-- Note inner for(j... has been removed
fread(&green, 1, 1, src);
fread(&blue, 1, 1, src);
fprintf(dest, "%u %u %u ",
(unsigned int)red,
(unsigned int)green,
(unsigned int)blue);
...
此外,我在http://netpbm.sourceforge.net/doc/ppm.html读取的规范表明,样本不一定是一个字节,具体取决于“...最大颜色值(Maxval)...”的值,您似乎存储在depth
。
编辑#1: 我拿出你的内在循环的原因......
for (i = 0; i < width*height; i++)
{
for (j = 0; j < 3; j++)
{
fread(&red, sizeof(int), 1, src);
fread(&green, sizeof(int), 1, src);
fread(&blue, sizeof(int), 1, src);
}
...是因为它读取9个字节,但只存储读取的最后3个字节的值。这是因为在第一次循环迭代中,您分别读取3个字节并将它们存储在变量red
,green
和blue
中。然后循环重复并将新数据读入这些变量。因此,最后一组数据丢失等等......
为什么把它放回来帮助我不知道?!这意味着可用的像素数据字节比我读到的标准要多。它表示宽度*高度像素,至少是我读它的方式,但是使用for(j...
循环读取3 *宽*高度。
鉴于我们所看到的(见问题中的评论)看起来没有这个循环你没有阅读足够的样本,但从标准来看,我不明白为什么(还):)
编辑2: 如果你试试....
unsigned char red, green blue;
...
for (i = 0; i < width*height; i++)
{
for (j = 0; j < 3; j++)
{
fread(&red, 1, 1, src);
fread(&green, 1, 1, src);
fread(&blue, 1, 1, src);
fprintf(dest, "%u %u %u ",
(unsigned int)red,
(unsigned int)green,
(unsigned int)blue);
if (widthCounter == width)
{
fprintf(dest, "\n");
widthCounter = 1;
}
else
widthCounter++;
}
}