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

标签 c image converters 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

最佳答案

根据我们在该问题的评论线程中的讨论,我认为问题出在您对二进制数据的读取上。

如果每个样本是一个字节,您将希望对红色/蓝色/绿色变量使用 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: 我取出你的内部 j 循环的原因...

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*width*height。

鉴于我们所看到的(参见问题中的评论)看起来没有这个循环你没有阅读足够的样本,但从标准来看,我不明白为什么(还):)

编辑 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++;

    }
}

关于c - 从文件中读取二进制数并将其保存为整数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18334290/

相关文章:

c - 32位浮点除法并没有我想象的那么慢

android - 在android中从https URL下载和保存图像

java - 回收器 View 中的空对象引用

mysql - 将多行mysql字符串转换为预定义的csv格式?

python - 使用 Python 将 PDF 转换为图像

javascript - 在 AngularJS 中使用过滤器 onclick 进行毫米 - 英寸转换器

c - 在 Erlang C NIF 中操作二进制文件

c - 从 C 中的字符串中提取整数

C:使用 fgets 读取用户输入时出现段错误

c# - 在 ExtJs Grid (C#) 中显示来自 SQL Server 数据库的图像的优雅方式