从文件中读取二进制数并将其保存为整数

时间:2013-08-20 11:51:08

标签: c image converter ppm

我正在尝试编写从P6到P3的转换器,这意味着从以二进制保存的数据到以ASCII保存的数据。

这是我为完成这项工作而编写的函数,但redgreenblue整数获取垃圾值而不是十进制值。

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;
}

读取二进制数据我做错了什么?完美阅读高度,宽度和深度。

编辑:在尝试使用读取数据大小后,我得到了一些我无法解释的疯狂结果: http://i.imgur.com/qUyjUca.png http://i.imgur.com/5BcofMl.png

2 个答案:

答案 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个字节并将它们存储在变量redgreenblue中。然后循环重复并将新数据读入这些变量。因此,最后一组数据丢失等等......

为什么把它放回来帮助我不知道?!这意味着可用的像素数据字节比我读到的标准要多。它表示宽度*高度像素,至少是我读它的方式,但是使用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++;

    }
}