代码之家  ›  专栏  ›  技术社区  ›  baudcode

没有所有编解码器信息的jpeg文件有多大?

  •  -2
  • baudcode  · 技术社区  · 7 年前

    我想知道如果没有jpeg的元、头和编解码器信息,jpeg文件有多大。因此,最终您将只检索压缩的像素数据,我认为它由DCT系数、量化和哈夫曼表组成。

    但是,如何使用Python或C/C++提取这些数组的大小呢?

    我确实尝试使用libjpeg,但没有找到计算压缩数据大小的方法。

    2 回复  |  直到 7 年前
        1
  •  0
  •   Mats Petersson    7 年前

    下面是一段代码,大致完成了要求的操作。我认为任何图书馆都没有现成的解决方案。

    它不是非常整洁,也不像我希望的那么简单。我已经从我的“~/图片”文件夹中随机运行了数百张图像(其他地方还有一些),但不能保证它能处理“任何”图像——我认为我所有的图像都是由两个不同的应用程序创建的。“其他一些”可能不会,但同样,不同的生产者可能会使用不同的字段,或者以这种代码无法处理的形式生成数据。如果它坏了,你可以保留所有的东西,但不退款。

    我将把它留给读者来确定什么是实际的图像数据,什么不是。请注意,块大小不包括块头本身,即顶部的另一个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);
    }
    
        2
  •  0
  •   user3344003    7 年前

    元数据的数量完全取决于编码器。JPEG流中唯一需要的头是2字节SOI标记。唯一的页脚是2字节EOI标记。

    其他任何东西都是编码器输入的。