jpegのメタ、ヘッダー、およびコーデック情報がないとjpegファイルの大きさを知りたいです。最後に、DCT係数と量子化とハフマンテーブルからなる圧縮されたピクセルデータのみを取得します。JPEGコーデックの情報がないJPEGファイルのサイズはどれくらいですか?
しかし、これらの配列のサイズをPythonまたはC/C++で抽出するにはどうすればよいですか?
私はのlibjpegを使用しようとしなかったが、圧縮されたデータのサイズを計算する方法を見つけることができませんでした。
jpegのメタ、ヘッダー、およびコーデック情報がないとjpegファイルの大きさを知りたいです。最後に、DCT係数と量子化とハフマンテーブルからなる圧縮されたピクセルデータのみを取得します。JPEGコーデックの情報がないJPEGファイルのサイズはどれくらいですか?
しかし、これらの配列のサイズをPythonまたはC/C++で抽出するにはどうすればよいですか?
私はのlibjpegを使用しようとしなかったが、圧縮されたデータのサイズを計算する方法を見つけることができませんでした。
おおよそのことをするコードです。私は、これがどのライブラリでも利用可能な「既製の」ソリューションがあるとは思わない。
これは非常にきれいではなく、私が望むほど単純ではありません。私は "〜/ Pictures"フォルダ(そして他の場所ではいくつか)から数百のランダムなイメージを走らせましたが、 "any"イメージを扱うという保証はありません - 私はすべてのイメージが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);
}
残念ながら、一部の画像でのみ動作します。これらのようなものは失敗します: https://imgur.com/a/YvrOc。 – baudcode
「うまくいかない」とは、どういう意味ですか?私はそれらの画像をダウンロードし、それらはすべていくつかの出力でプログラムを通過する - 私はそれが何であるべきで、何がすべきかに何の努力もしていないが、出力は一般的にOKと思われる。これはもちろん、画像は実際にアップロードしたものと同じではないことがあります(多くのサイトでアップロードプロセスの一部として画像がコード化されていますが、主にサイズを縮小するため)。そのため、問題が再現可能かどうかを確認したい場合がありますあなたのリンクから画像をダウンロードしてください。次に、何が起こっているのかを詳しく説明します。 –
申し訳ありませんが、私のコードのバグでした:(すべてが完璧に動作します。 – baudcode
メタデータの量は、エンコーダに完全に依存している。JPEGストリームで必要がありヘッダのみです2バイトのSOIマーカーです。唯一のフッターは2バイトのEOIマーカーです。
他のものは何でもありません彼はエンコーダーを入れます。
実際には、そのエンコーダは妥当な量を追加しています。私はヘッダーフィールドからJPEGファイルにあるものを読み出すプログラムを書き始めましたが、マーカーと長さを読み取るだけでは少し複雑です。しかし、4.1Kのデータファイルには3160バイトのメタデータが含まれています(私が今話す限り)。これはGIMPのものです。より低い圧縮設定(同じピクチャでより詳細)を有する同じ入力ファイルは、同じ3160バイトのメタデータを有するように見える。 –
エンコーダによって異なります。私のものは誰も追加しない。 – user3344003
これはどちらですか?または自家製のもの?私はBaudcodeが自家製ではないエンコーダからの既知の量のオーバーヘッドがないので、それがどれほどあるかを知りたいと思っていました。 –
私はかなり確信してのlibjpegだ[私はちょうど今それのためのドキュメントを読んで]:私の最高のすべてのコーディング...
が、私はここにもするコードを追加した意味がないことにより、あなたにこの情報を与えることはありません(直接、ソースに変更はありません)。 PythonのJPEGコードはlibjpegに基づいているので、どちらも役に立ちます。ヘッダーなどを読み取るコードを記述してから、全体のサイズからメタデータサイズを減算するだけです。 –
なぜ知りたいですか?メタデータがなければ、残りは役に立たなくなります。 –
私は、JPEGファイルの開始時に約9バイトの純粋に識別データがあると信じています。デコードには他のすべてが必要です。 –