匹配JPEG签名

时间:2014-07-07 19:29:40

标签: c file-io jpeg

我正在尝试扫描一个文件,查找将连续存储的1MB JPEG。我的方法是创建一个结构,将前4个字节与JPEG签名匹配,如果为true,则将整个512缓冲区写入命名文件,直到找到另一个jpeg签名,然后创建一个新文件。下面的代码创建了2个文件,这两个文件都不可读,因为前几个字节不是jpeg签名的一部分。我出错的任何想法?我尝试了我的if语句的变体,我在那里测试签名但到目前为止没有运气。

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

typedef uint8_t  BYTE;

typedef struct
{
    BYTE first;
    BYTE second;
    BYTE third;
    BYTE fourth;
}
JPGTEST;

int main(int argc, char* argv[])
{

    FILE* inptr = fopen("card.raw", "r");

    if (inptr == NULL)

    {

        printf("Could not open file\n");

        return 2;

    }

    FILE* outptr;

    //initialize jpeg count and variable for filename
    int count = 0;
    char name[8];

    //allocate memory
    char buffer[512];
    JPGTEST myjpg;
    int is_open = 0;

    while (fread(&buffer, 512, 1, inptr) != 0)
    {

        //test first 4 bytes to see if jpeg
        fread(&myjpg, sizeof(JPGTEST), 1, inptr);

        //if match, name and write to file

        if (myjpg.first == 0xff && myjpg.second == 0xd8 && myjpg.third == 0xff && (myjpg.fourth == 0xe0 || myjpg.fourth == 0xe1))
        {
            sprintf(name, "%03d.jpg", count);
            if (is_open == 0)
            {          
                outptr = fopen(name, "w");
                fwrite(buffer, sizeof(buffer),1,outptr);
                is_open = 1;
            }
            if (is_open == 1)
            {          
                fclose(outptr);
                outptr = fopen(name, "w");
                fwrite(buffer, sizeof(buffer),1,outptr);
                count++;
            }  

        }
        else
        {
            if (is_open == 1)
            {
                fwrite(buffer, sizeof(buffer),1,outptr);
            }
        }
    }
    fclose(inptr);
    fclose(outptr);
    return 0;
}

4 个答案:

答案 0 :(得分:2)

您正在文字模式中打开文件。您需要以二进制模式打开它们:

FILE* inptr = fopen("card.raw", "rb");

outptr = fopen(name, "wb");

除此之外,您正在多次调用fread(),而且通常无法正确管理文件。

请尝试更多内容:

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

typedef uint8_t  BYTE;

#pragma pack(push, 1)
typedef struct
{
    BYTE first;
    BYTE second;
    BYTE third;
    BYTE fourth;
}
JPGTEST;
#pragma pack(pop)

int main(int argc, char* argv[])
{
    FILE* inptr = fopen("card.raw", "rb");
    if (inptr == NULL)
    {
        printf("Could not open file\n");
        return 2;
    }

    FILE* outptr = NULL;

    //initialize jpeg count and variable for filename
    int count = 0;
    char name[8];

    //allocate memory
    char buffer[512];
    JPGTEST myjpg;

    while (fread(buffer, sizeof(buffer), 1, inptr) > 0)
    {
        //test first 4 bytes to see if jpeg
        memcpy(&myjpg, buffer, sizeof(JPGTEST));

        //if match, name and write to file
        if ((myjpg.first == 0xff) && (myjpg.second == 0xd8) && (myjpg.third == 0xff) && ((myjpg.fourth == 0xe0) || (myjpg.fourth == 0xe1)))
        {
            if (outptr != NULL)
            {          
                fclose(outptr);
                outptr = NULL;
            }

            ++count;
            sprintf(name, "%03d.jpg", count);

            outptr = fopen(name, "wb");
        }

        if (outptr != NULL)
            fwrite(buffer, sizeof(buffer), 1, outptr);
    }

    fclose(inptr);

    if (outptr != NULL)
        fclose(outptr);

    return 0;
}

答案 1 :(得分:1)

使用以下内容替换循环内的第二个 fread

        memcpy((void *)&myjpg, (void *) buffer, sizeof(JPGTEST));

memcpy 函数的代码中包含string.h头文件。

你所做错的是,在读完第512页后你没有使用它们,而是你再次读取4个字节而不检查先前读取的512字节的前4个字节。

答案 2 :(得分:0)

问题是您在阅读buffer后没有重置文件位置指示符,为此请使用fseek。即:

    //test first 4 bytes to see if jpeg
    fseek (inptr, SEEK_SET, 0);
    fread(&myjpg, sizeof(JPGTEST), 1, inptr);

这将为您提供myjpg中的jpg标题的测试:

sizeof (myjpg): 4
first: ff  second: d8  third ff  fourth:  e0

但是,这也会导致您必须返工的逻辑问题。最好只读取buffer中的值,如另一个答案所示。

答案 3 :(得分:0)

您可以执行以下操作来简化签名比较:

#include ...

#define JPEG_SIGNATURE 0xFFD8

void
reverse_bytes (void const *data, long unsigned size)
{
  char *ptr = (char *)data;
  int i = 0;
  while (i < size / 2)
    {
      char temp = ptr[i];
      ptr[i] = ptr[size - i - 1];
      ptr[size - i - 1] = temp;
      i++;
    }
}

int
main()
{
  FILE *fptr = fopen("path/to/image.jpeg", "rb");

  short bytes = 0;
  fread(&bytes, sizeof(char), sizeof(bytes), fptr);

  reverse_bytes(bytes, sizeof(bytes)); // Refer to [1]

  switch (bytes)
  {
    case JPEG_SIGNATURE: 
      printf("JPEG image!");
      break;
    default:
      printf("Unknown format!");
      break;
  }

  return 0;
}

这可以通过在 switch 语句中添加更多 case 和更多工作来扩展到许多不同的格式。

这确实不是一个完整或正确的答案,但我希望它对其他人通过这篇文章有所帮助!

注意:为简洁起见,我省略了诸如异常处理之类的内容!

参考:

  1. Why is Fread reading unsigned-int in reverse order?