c - 使用 C 从 .raw 文件恢复 JPEG 图像

标签 c image cs50

我正在做 Harvard's online lecture 提供的问题集. 我终于找到了从文件 (card.raw) 中恢复一组 JPEG 图像的解决方案。

似乎代码本身并没有抛出错误,但它返回的是扭曲的图像,我有点不知道为什么会发生这种情况。

[链接到图像示例] https://prnt.sc/q0tb4f

这是我的代码

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>


int main(int argc, char *argv[])
{
    //check usage
    if (argc != 2)
    {
        return 1;
    }
    // open file
    FILE* input = fopen(argv[1], "r");
    // return error if file does not existS
    if (!input)
    {
        return 1;
        printf("file does not exists");
    }
    // create an array with 512 bytess of bytes
    unsigned char bytes[512];
    // create count variable
    int count = 0;
    // create an empty string for filename
    char filename[7];
    // create an empty output file
    FILE* output = NULL;
    // repeat until end of input
    while (fread(bytes, 1, sizeof(bytes), input) != 0)
    {
        // read 1 block of 512 bytes at a time
        fread(bytes, 1, sizeof(bytes), input);

        // check if beginning of jpeg file
        if (bytes[0] == 0xff && bytes[1] == 0xd8 && bytes[2] == 0xff && (bytes[3] & 0xf0) == 0xe0)
        {
            // if already found a jpeg, close the file
            if (count > 0)
            {
                fclose(output);
            }
            // name file
            sprintf(filename, "%03i.jpg", count);
            // open file
            output = fopen(filename, "w");
            // write file
            fwrite(bytes, 1, sizeof(bytes), output);
            // increment count
            count++;
        }
        if (output != NULL)
        {
            // keep writing if jpeg header is already found
            fwrite(bytes, 1, sizeof(bytes), output);
        }
    }
     fclose(output);
     fclose(input);
}

我没有受过教育的假设无法理解为什么会发生这种情况。 我只能想象这可能是由于在不正确的步骤中打开和关闭文件而发生的。

最佳答案

问题是:

while (fread(bytes, 1, sizeof(bytes), input) != 0)
{
    // read 1 block of 512 bytes at a time
    fread(bytes, 1, sizeof(bytes), input);

您在每个循环中调用两次 fread。结果,循环体只能看到奇数 block 。删除第二个 fread

第二个问题(如 @SteveFriedl 指出的那样)是代码用于文件名的缓冲区太小。

char filename[7];
sprintf(filename, "%03i.jpg", count);

像“123.jpg”这样的文件名至少需要 8 个字节,因为您需要为 NUL 终止符留出空间。但是,请注意 "%03i" 使用至少 3 个字符。它可以使用更多,例如如果 count 达到 1000。所以我会将缓冲区声明为 char filename[32]; 以避免任何缓冲区溢出的机会。

当只需要一个时,您还有两个 fwrites:

        output = fopen(filename, "w");
        // write file
        fwrite(bytes, 1, sizeof(bytes), output);
        // increment count
        count++;
    }
    if (output != NULL)
    {
        // keep writing if jpeg header is already found
        fwrite(bytes, 1, sizeof(bytes), output);
    }

打开一个新文件后,代码写入第一个 block ,然后再次写入。删除第一个 fwrite 并让第二个 fwrite 处理第一个 block 。

另一个问题是代码做了一个隐含的假设,即如果 fread 不返回 0,那么它会读取一个完整的 block 。如果文件大小是 block 大小的倍数,那么该假设是可以的,但最好不要做任何假设。所以while循环中的条件应该是

while (fread(bytes, 1, sizeof(bytes), input) == sizeof(bytes))

关于c - 使用 C 从 .raw 文件恢复 JPEG 图像,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59002783/

相关文章:

python - R_PPC_REL24 重定位超出范围

c - 如何将文本文件传递到c中的数组中?

c# - 图像透明度与另一个向后 c#

jquery - Feed 图像显示在某些浏览器中旋转

c - 程序在等待退出时超时

c - 如何在For循环中输入两个条件?

c - "volatile"是否能保证多核系统的可移植 C 代码中的任何内容?

自定义 float 加法,实现数学表达式 - C

image - 是否可以在 Sprite 图像中重复背景条

cs50函数 'get_int'的隐式声明在mario的C99中无效