c - 图像恢复程序有问题

标签 c jpeg cs50

基本上,我为我的计算机类(class)(大喊 CS50)编写了这个程序,用于从 .raw 文件恢复图像。我已成功让程序恢复了该文件中 50 个文件中的 48 个。

我现在遇到的问题是该程序无法恢复位于 .raw 上的第一个和第二个文件。它要么读取并写入第一个文件(这个在雪地背景中的女孩),要么读取和写入 .raw 上的第二个文件(书籍背后的人)。

出于某种原因,如果我将 fopen 从 write 更改为追加,我可以在女孩和男孩的照片之间切换,但我似乎无法打开两者。

https://github.com/CoreData/cs50/blob/master/pset4/jpg/card.raw 这是card.raw的链接,不幸的是它与我使用的不是同一个,但即使使用这个,你也会得到两个不同的image1.jpg图像,具体取决于你的fopen是否带有“a”或“w”。

有什么想法吗???

如果你们想要任何其他信息,请告诉我

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

#include "bmp2.h"

int main(void)
{
    /*OPEN CARD FILE*/
    char* infile = "card.raw";;

    FILE* card = fopen(infile, "r");
    if (card == NULL)
    {
        printf("Could not open %s.\n", "card.raw");
        return 2;
    }

    int f = 0, c = 0, l = 0, x = 128, imageno = 1;
    // c signals that a jpg is being written
    // l size control, 0 means 0 jpgs
    FILE* images;
    char* title = (char*)malloc(15);

    /*repeat until end of card*/
    do
    {
        //read one block into buffer
        INTROJPG *buffer = (INTROJPG*)malloc(sizeof(INTROJPG)*x);

        for (int i = 0; i < 128; i++)
        {
            fread(&buffer[i], sizeof(INTROJPG), 1, card);
        }

        if (buffer[0].first == 0xff && buffer[0].second == 0xd8 && buffer[0].third == 0xff)
        {
            sprintf(title, "image%d.jpg", imageno); //change jpg title

            if (f == 1) //close previous jpg
            {
                fclose(images);
                imageno++;
            }

            images = fopen(title, "w");
            f = 1; //very first jpg has been opened
            c = 1; //jpg open
            l++; //jpg count + 1
        }

        //jpg already open?
        if (c == 1)
        {
            for (int i = 0; i < 128; i++)
            {
                fwrite(&buffer[i], sizeof(INTROJPG), 1, images);
            }
        }
        free(buffer);
    }    
    while (l < 50);
    free(title);
    return 5;
        //close any remaining files
}


and this is my bmp2.h file

    #include <stdint.h>

/**
 * Common Data Types 
 *
 * The data types in this section are essentially aliases for C/C++ 
 * primitive data types.
 *
 * Adapted from http://msdn.microsoft.com/en-us/library/cc230309.aspx.
 * See http://en.wikipedia.org/wiki/Stdint.h for more on stdint.h.
 */
typedef uint8_t  BYTE;
typedef uint32_t DWORD;
typedef int32_t  LONG;
typedef uint16_t WORD;

/**
 * BITMAPFILEHEADER
 *
 * The BITMAPFILEHEADER structure contains information about the type, size,
 * and layout of a file that contains a DIB [device-independent bitmap].
 *
 * Adapted from http://msdn.microsoft.com/en-us/library/dd183374(VS.85).aspx.
 */
typedef struct 
{ 
    WORD   bfType; 
    DWORD  bfSize; 
    WORD   bfReserved1; 
    WORD   bfReserved2; 
    DWORD  bfOffBits; 
} __attribute__((__packed__)) 
BITMAPFILEHEADER; 

/**
 * BITMAPINFOHEADER
 *
 * The BITMAPINFOHEADER structure contains information about the 
 * dimensions and color format of a DIB [device-independent bitmap].
 *
 * Adapted from http://msdn.microsoft.com/en-us/library/dd183376(VS.85).aspx.
 */
typedef struct
{
    DWORD  biSize; 
    LONG   biWidth; 
    LONG   biHeight; 
    WORD   biPlanes; 
    WORD   biBitCount; 
    DWORD  biCompression; 
    DWORD  biSizeImage; 
    LONG   biXPelsPerMeter; 
    LONG   biYPelsPerMeter; 
    DWORD  biClrUsed; 
    DWORD  biClrImportant; 
} __attribute__((__packed__))
BITMAPINFOHEADER; 

/**
 * RGBTRIPLE
 *
 * This structure describes a color consisting of relative intensities of
 * red, green, and blue.
 *
 * Adapted from http://msdn.microsoft.com/en-us/library/aa922590.aspx.
 */
typedef struct
{
    BYTE  rgbtBlue;
    BYTE  rgbtGreen;
    BYTE  rgbtRed;
} __attribute__((__packed__))
RGBTRIPLE;


typedef struct
{
    BYTE first;
    BYTE second;
    BYTE third;
    BYTE fourth;
} __attribute__((__packed__))
INTROJPG;

typedef struct
{
    BYTE image;
}
BYTEIMAGE;

最佳答案

首先,我将尝试改进您的代码中的一些内容。我也完成了这个 pset,很高兴能帮助其他人。

INTROJPG *buffer = (INTROJPG*)malloc(sizeof(INTROJPG)*x);

在这一部分,您知道 INTROJPG 和 x 的大小都是恒定的,因此不需要在每次迭代时不断分配和释放内存,这比简单创建普通数组花费更多时间。另外,为什么缓冲区是指向 INTROJPG 的指针?如果只是在每次迭代时测试 header ,我认为不值得,您可以简单地访问普通 BYTE 数组的前 4 个字节。

我会创建一个 512 BYTE 的静态数组(库上的结构),因为这是您不断分配和释放的大小,而且您使用的是 BYTE,而不是 INTROJPG。

第二,在本节和另一个类似的节中:

for (int i = 0; i < 128; i++)
{
    fread(&buffer[i], sizeof(INTROJPG), 1, card);
}

绝对不需要这个循环,甚至不需要使用 INTROJPG。你总是读写 512 字节,你可以使用:

fread(buffer, 4, 128, card);
// or even better
fread(buffer, 512, 1, card);

现在关于你的问题,我已经多次测试了你的代码(没有任何修改),发现 image1.jpg 和 image2.jpg 没有任何问题。是的,我将“w”模式更改为“a”,反之亦然。

但是,您的代码对于最后一个图像是错误的,您的最后一个图像是image49.jpg,而它应该是image50.jpg,而您的image49.jpg甚至没有打开,那是因为循环之前完成image49.jpg 的其余部分被存储,即,您仅存储 image49.jpg 的前 512 个字节。

为了解决这个问题,我更改了 do-while 循环的条件,使其继续运行直到卡文件末尾,IIRC 问题保证最后一个 block 是最后一个图像的一部分或类似的东西,如果不是的话,这个小问题就靠你来解决了!

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

#include "bmp2.h"

int main(void)
{
    /*OPEN CARD FILE*/
    char* infile = "card.raw";;

    FILE* card = fopen(infile, "r");
    if (card == NULL)
    {
        printf("Could not open %s.\n", "card.raw");
        return 2;
    }

    int f = 0, c = 0, imageno = 1;
    // c signals that a jpg is being written
    // l size control, 0 means 0 jpgs
    FILE* images;
    char title[25];
    BYTE buffer[512];

    /*repeat until end of card*/
    do
    {

        fread(buffer,  512, 1, card);

        if (buffer[0] == 0xff && buffer[1] == 0xd8 && buffer[2] == 0xff)
        {
            sprintf(title, "image%d.jpg", imageno); //change jpg title

            if (f == 1) //close previous jpg
            {
                fclose(images);
                imageno++;
            }

            images = fopen(title, "w");
            f = 1; //very first jpg has been opened
            c = 1; //jpg open
        }

        //jpg already open?
        if (c == 1) fwrite(buffer, 512, 1, images);
    }    
    while (!feof(card));
    return 5;
        //close any remaining files
}

最后一件事,为什么你在程序结束时返回 5?只是好奇。

关于c - 图像恢复程序有问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39351118/

相关文章:

c - while (getchar () != '\n' );

python - 为什么 jpeg 不能从 django 正确保存到 AWS S3

java - 尽管构建没有错误,CS50 Android Track Filter 将无法在设备中运行

c - 如何将残数与长长数分开?

c - 错误: expected expression in else if statement

c - C 中的 “How to fix ‘format string is not a string literal (potentially insecure)’ 错误”

c - 如何用纯c创建图形 Canvas 来显示图形而无需任何库和平台独立

c++ - 分配两个数组一次调用 cudaMalloc

video - 与 Shell 脚本一起使用时在哪里添加 FilterChain

Android:在 PDF 文档中嵌入压缩图像