【问题标题】:Extracting jpeg files from file in C从C中的文件中提取jpeg文件
【发布时间】:2015-10-21 07:53:59
【问题描述】:

我正在尝试从类似存储卡的文件中提取 jpeg 文件。该程序将一次读取 512 个字节的块,如果该块以 JPEG 识别字节开头,我的程序应该将这些字节写入输出文件。它应该继续写入这些字节,直到它找到另一个 JPEG 识别字节序列,此时它应该停止写入 .jpg 文件并写入新文件。每个文件应命名为 00x.jpg,其中 x 是 #。

我的程序可以编译,但没有生成所有的 jpeg。应该有 16 个 JPEG,但它只生成 7 个。

int main(void)
{
    // open file for reading
    FILE* file = fopen("card.raw", "r"); // Open the file for reading

    // target file
    FILE* image;

    // buffer of bytes
    uint8_t buffer[512];        

    // check for NULL file
    if (file == NULL)
    {
        fclose(file);
        printf("Could not open file");
        return 1;
    }

    // Prefixes of a jpeg file
    uint8_t jpeg1[4] = {0xff, 0xd8, 0xff, 0xe0};
    uint8_t jpeg2[4] = {0xff, 0xd8, 0xff, 0xe1};

    // keep track of jpegs opened
    int pic = 0;

    int match = 0;

    // is file open?
    int open = 0;


    // stores first 4 bytes of block
    uint8_t check[4];

    int byteNum;
    byteNum = fread(buffer, 512, 1, file);

    // while there are bytes to be read in the file
    while(fread(buffer,512, 1, file) > 0)
    {
        for (int x=0; x < 4; x++)
        {
            check[x] = buffer[x];
        }

        // compares first 4 bytes of buffer segment to jpeg prefixes to determine match
        if((memcmp(check, jpeg1,4) == 0) || (memcmp(check, jpeg2, 4) == 0))
        {

            match = 1;   
        }
        // if encounter a jpeg and file is open, close the file and set match to false
        if (match == 1 && open == 1)
        {


            fclose(image);
            open = 0;        
            match = 0;
        }

        // if match is true and file is closed, create jpeg output file, increment pic#, set file to open, set match to false, open target file
        if (match == 1 && open == 0)
        {
            // stores name of jpegfile
            char jpegName[8]; 
            // stores the jpeg file name with the # jpeg          
            sprintf(jpegName ,"%03d.jpg" ,pic); 
            pic++;
            open = 1; // signifies target jpeg file is open
            match = 0; // sets match back to 0 (false) so it can detect the next match to signify closing the writing            
            image=fopen(jpegName, "w"); // write to target file image
        }

        // if file target is still open but no match, then keep writing since you're in the middle of a jpeg
        if (match == 0 && open == 1)
        {
            fwrite(buffer, 512, 1, image);
        }

    }

    fclose(file);
    return 0;
}

【问题讨论】:

  • 仅供参考,如果这开始写入,您将写入每个文件的前 512 个字节两次。首先当match==1 &amp;&amp; open == 0,你设置open = 1;,打开文件,写入数据,设置match = 0;,然后在你检查match == 0 &amp;&amp; open == 1)之后立即,因为你只是这样设置的,所以您再次编写相同的块。第一个fwrite 似乎不需要在那里。
  • 你是对的。我删除了那个。还是不输出jpg。
  • 哦,这不是唯一的问题,只是我注意到的一个问题。这需要通过调试器来验证您所做的所有假设。例如:你永远不会增加pic,所以你总是写入相同的目标文件名000.jpg
  • 使用调试器、设置断点、单步执行代码、将预期值与找到的值进行比较等
  • 应该是 while(fread(buffer,512, 1, file) > 1)。我进行了更改,但现在得到了:双重释放或损坏(顶部)...我将继续调试。

标签: c file-io jpeg


【解决方案1】:

我可能遗漏了一些明显的东西,但是如果您要做的只是读取 512 字节块中的文件,检查每个块的前四个八位字节是否有两个已知的前导码,然后在遇到任何一个时,打开一个图像文件并开始转储,直到下一个匹配的块关闭文件并开始一个新的,然后大约一半的发布代码是不需要的。

您可以使用image 的值(是否为空)来指示文件是否打开。此外,仅在打开文件时写入数据(image != NULL),如果在循环到下一个文件之前打开现有文件,则关闭现有文件。

类似这样的:

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

int main(void)
{
    // Prefixes of a jpeg file
    static const uint8_t jpeg1[4] = {0xff, 0xd8, 0xff, 0xe0};
    static const uint8_t jpeg2[4] = {0xff, 0xd8, 0xff, 0xe1};

    // open file for reading
    FILE* file = fopen("card.raw", "r"); // Open the file for reading
    if (file == NULL)
    {
        perror("card.raw");
        return EXIT_FAILURE;
    }

    // target file
    FILE* image = NULL;

    // keep track of jpegs opened
    int pic = 0;

    // while there are bytes to be read in the file
    uint8_t buffer[512];
    size_t n_bytes = 0;
    while( (n_bytes = fread(buffer,1, 512, file)) > sizeof(jpeg1))
    {
        // compares first 4 bytes of buffer segment to jpeg prefixes to determine match
        if( memcmp(buffer, jpeg1, sizeof(jpeg1)) == 0 ||
            memcmp(buffer, jpeg2, sizeof(jpeg2)) == 0)
        {
            // stores the jpeg file name with the # jpeg
            char jpegName[64];
            sprintf(jpegName ,"00%d.jpg" , pic++);

            // match. close current file if present.
            if (image)
                fclose(image);

            // open new image file (sets NULL on failure)
            image = fopen(jpegName, "wb"); // write to target file image
            if (image == NULL)
            {
                perror(jpegName);
                break;
            }
        }

        // write whatever we have for our current bytes
        if (image)
            fwrite(buffer, n_bytes, 1, image);
    }

    // the above loop can exit with a file open (in fact, it is guaranteed
    // if we opened at least one file), so close it if one is active.
    if (image)
        fclose(image);
}

或类似的东西。这也会以二进制模式打开和关闭文件,并且如果最后一帧小于 512 字节,则不会在最后一帧写入无关的垃圾。最后,它会在创建的每个文件上增加pic,并进行(诚然是软的)错误检查。

无论如何,希望它有所帮助。祝你好运。

【讨论】:

    猜你喜欢
    • 2012-02-03
    • 1970-01-01
    • 2012-05-08
    • 1970-01-01
    • 2018-01-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多