下面是一段代码,大致完成了要求的操作。我认为任何图书馆都没有现成的解决方案。
它不是非常整洁,也不像我希望的那么简单。我已经从我的“~/图片”文件夹中随机运行了数百张图像(其他地方还有一些),但不能保证它能处理“任何”图像——我认为我所有的图像都是由两个不同的应用程序创建的。“其他一些”可能不会,但同样,不同的生产者可能会使用不同的字段,或者以这种代码无法处理的形式生成数据。如果它坏了,你可以保留所有的东西,但不退款。
我将把它留给读者来确定什么是实际的图像数据,什么不是。请注意,块大小不包括块头本身,即顶部的另一个2字节。
哦,是的,这是C++和C的混合体。我只是把它和我为了不同的目的而编写的部分代码结合在一起,并将其整理好,所以它不是一团乱麻,但它绝不是我最好的每一个代码。。。
我还在此处添加了代码:
https://github.com/Leporacanthicus/jpegrd
#include <fstream>
#include <ios>
#include <vector>
#include <cstdint>
#define die(str, ...) \
do { printf(str, __VA_ARGS__); exit(1); } while(0)
void read_bytes(std::ifstream &f, uint8_t *buffer, std::streamsize sz)
{
if(!f.read(reinterpret_cast<char*>(buffer), sz))
{
die("Expected to read %zd bytes\n", sz);
}
}
uint32_t read_size(std::ifstream &f)
{
uint8_t buffer[2];
read_bytes(f, buffer, 2);
uint32_t size = buffer[0] << 8 | buffer[1];
return size;
}
void skip_size(std::ifstream &f, std::streamsize to_skip)
{
f.seekg(to_skip - 2, std::ios_base::cur);
}
void check_buffer(uint8_t *buffer, const std::vector<uint8_t> &val)
{
uint8_t *b = buffer;
for(auto v : val)
{
if (*b != v)
{
die("Mismatch! Expected %02x, got %02x\n", v, *b);
}
b++;
}
}
uint32_t find_next_header(std::ifstream &f)
{
uint8_t b;
bool found = false;
uint32_t count = 0;
do
{
read_bytes(f, &b, 1);
if (b == 0xFF)
{
if (f.peek() == 0x00)
{
read_bytes(f, &b, 1);
count+= 2;
}
else
{
f.unget();
found = true;
}
}
else
{
count++;
}
} while(!found);
return count;
}
int main(int argc, char **argv)
{
if (argc != 2)
{
printf("Expected filename as argument\n");
exit(1);
}
std::ifstream f(argv[1], std::ios_base::in|std::ios_base::binary);
if (!f)
{
die("Couldn't open the file %s\n", argv[1]);
}
uint8_t buffer[2];
uint32_t total = 0;
read_bytes(f, buffer, 2);
check_buffer(buffer, {0xFF, 0xd8});
total += 2;
bool eoi = false;
do
{
uint32_t size;
read_bytes(f, buffer, 2);
if (buffer[0] != 0xff)
{
die("Expected 0xFF byte, got %02x at offset %zu\n",
buffer[0], (size_t)f.tellg());
}
total += 2;
switch(buffer[1])
{
case 0xE0:
case 0xE1:
case 0xE2:
case 0xE3:
case 0xE4:
case 0xE5:
case 0xE6:
case 0xE7:
case 0xE8:
case 0xE9:
case 0xEA:
case 0xEB:
case 0xEC:
case 0xED:
case 0xEE:
case 0xEF:
size = read_size(f);
total += size;
printf("APP Data Type %02x: %u bytes of application data\n",
buffer[1], size);
skip_size(f, size);
break;
case 0xDB:
size = read_size(f);
total += size;
printf("DQT: %u bytes of quantization data\n", size);
skip_size(f, size);
break;
case 0xC0:
case 0xC2:
size = read_size(f);
total += size;
printf("SOF: %u bytes of frame data\n", size);
skip_size(f, size);
break;
case 0xC4:
size = read_size(f);
total += size;
printf("DHT: %u bytes of huffman tables\n", size);
skip_size(f, size);
break;
case 0xDA:
size = read_size(f);
skip_size(f, size);
size += find_next_header(f);
total += size;
printf("SOS: %u bytes of scan data\n", size);
break;
case 0xD9:
printf("EOI: end of image\n");
eoi = true;
break;
case 0xFE:
size = read_size(f);
skip_size(f, size);
total += size;
printf("COM: comment %u bytes\n", size);
break;
default:
die("Expected known encoding byte, got %02x\n", buffer[1]);
break;
}
} while(!eoi);
printf("Total size = %u\n", total);
}