0

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

这是我为完成这项工作而编写的函数,但是整数red得到的是垃圾值而不是十进制值。greenblue

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

4

2 回答 2

1

好的,问题出在 fread 上。您正在从文件中读取

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/

于 2013-08-20T12:46:48.217 回答
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:我取出你的内部 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++;

    }
}
于 2013-08-20T12:49:37.577 回答