使用 C 从 .raw 文件恢复 JPEG 图像
Recovering JPEG image from .raw file using C
我正在做 Harvard's online lecture 提供的习题集。
我终于找到了从文件中恢复一组 JPEG 图像的解决方案 (card.raw)。
似乎代码本身并没有抛出错误,但它返回的是扭曲的图像,我有点不知道为什么会这样。
[Link 以图像为例] 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
两次。结果,循环体只能看到奇数块。删除第二个 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);
}
打开一个新文件后,代码写入第一个块,然后再次写入。删除第一个 fwrite
并让第二个 fwrite
处理第一个块。
另一个问题是代码隐式假设如果 fread
不是 return 0,那么它会读取一个完整的块。如果文件大小是块大小的倍数,那么该假设是可以的,但最好不要做任何假设。所以while
循环中的条件应该是
while (fread(bytes, 1, sizeof(bytes), input) == sizeof(bytes))
这里正在恢复工作。
#include <stdio.h>
#include <stdlib.h>
int isAJpg(unsigned char bytes[]);
int main(int argc, char *argv[])
{
if (argc != 2)
{
return 1;
}
FILE *file = fopen(argv[1], "r");
if (file == NULL)
{
return 1;
}
char filename[10];
int count = 0;
unsigned char bytes[512];
FILE *output;
int jpgfound = 0;
while (fread(bytes, 512, 1, file) != 0)
{
// if it is a jpg
if (isAJpg(bytes) == 1)
{
if (jpgfound == 1)
{
fclose(output);
}
else
{
jpgfound = 1;
}
// name file
sprintf(filename, "%03d.jpg", count);
// open file
output = fopen(filename, "a");
count++;
}
if (jpgfound == 1)
{
// writes to a file
fwrite(&bytes, 512, 1, output);
}
}
//close the files
fclose(output);
fclose(file);
}
// check in it is a jpg
int isAJpg(unsigned char bytes[])
{
if (bytes[0] == 0xff && bytes[1] == 0xd8 && bytes[2] == 0xff && (bytes[3] & 0xf0) == 0xe0)
{
return 1;
}
return 0;
}
我正在做 Harvard's online lecture 提供的习题集。 我终于找到了从文件中恢复一组 JPEG 图像的解决方案 (card.raw)。
似乎代码本身并没有抛出错误,但它返回的是扭曲的图像,我有点不知道为什么会这样。
[Link 以图像为例] 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
两次。结果,循环体只能看到奇数块。删除第二个 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);
}
打开一个新文件后,代码写入第一个块,然后再次写入。删除第一个 fwrite
并让第二个 fwrite
处理第一个块。
另一个问题是代码隐式假设如果 fread
不是 return 0,那么它会读取一个完整的块。如果文件大小是块大小的倍数,那么该假设是可以的,但最好不要做任何假设。所以while
循环中的条件应该是
while (fread(bytes, 1, sizeof(bytes), input) == sizeof(bytes))
这里正在恢复工作。
#include <stdio.h>
#include <stdlib.h>
int isAJpg(unsigned char bytes[]);
int main(int argc, char *argv[])
{
if (argc != 2)
{
return 1;
}
FILE *file = fopen(argv[1], "r");
if (file == NULL)
{
return 1;
}
char filename[10];
int count = 0;
unsigned char bytes[512];
FILE *output;
int jpgfound = 0;
while (fread(bytes, 512, 1, file) != 0)
{
// if it is a jpg
if (isAJpg(bytes) == 1)
{
if (jpgfound == 1)
{
fclose(output);
}
else
{
jpgfound = 1;
}
// name file
sprintf(filename, "%03d.jpg", count);
// open file
output = fopen(filename, "a");
count++;
}
if (jpgfound == 1)
{
// writes to a file
fwrite(&bytes, 512, 1, output);
}
}
//close the files
fclose(output);
fclose(file);
}
// check in it is a jpg
int isAJpg(unsigned char bytes[])
{
if (bytes[0] == 0xff && bytes[1] == 0xd8 && bytes[2] == 0xff && (bytes[3] & 0xf0) == 0xe0)
{
return 1;
}
return 0;
}