3

この関数を指定されたファイル名 (jpeg ファイル) に書き、そのサイズを w と h のピクセル単位で出力します。私が読んでいるチュートリアルによると、

//0xFFC0 は、ファイル サイズを含む「フレームの開始」マーカーです //0xFFC0 ブロックの構造は非常に単純です [0xFFC0][ushort length][uchar precision][ushort x][ushort y]

だから、私はこれを書いたstruct

#pragma pack(1)
struct imagesize {
  unsigned short len; /* 2-bytes */
  unsigned char c;    /* 1-byte */
  unsigned short x;   /* 2-bytes */
  unsigned short y;   /* 2-bytes */
}; //sizeof(struct imagesize) == 7
#pragma pack()

その後:

#define SOF 0xC0 /* start of frame */

    void jpeg_test(const char *filename)
    {
      FILE *fh;
      unsigned char buf[4];
      unsigned char b;

      fh = fopen(filename, "rb");
      if(fh == NULL) 
        fprintf(stderr, "cannot open '%s' file\n", filename);

      while(!feof(fh)) {
        b = fgetc(fh);

        if(b == SOF) {

          struct imagesize img;
    #if 1
          ungetc(b, fh);
          fread(&img, 1, sizeof(struct imagesize), fh);
    #else
          fread(buf, 1, sizeof(buf), fh);
          int w = (buf[0] << 8) + buf[1];
          int h = (buf[2] << 8) + buf[3];
          img.x = w;
          img.y = h;
    #endif

          printf("%dx%d\n",
             img.x,
             img.y);

          break;
        }
      }

      fclose(fh);
    }

しかし、私はの520x537代わりに取得700x537しています。それが実際のサイズです。

誰かが私が間違っている場所を指摘して説明できますか?

4

3 に答える 3

8

JPEG ファイルは、いくつかのセクションで構成されています。各セクションは で始まり、0xff1 バイトのセクション識別子、セクション内のデータ バイト数 (2 バイト単位)、データ バイトが続きます。データ バイト シーケンス内のシーケンス0xffc0またはその他の0xff--2 バイト シーケンスには意味がなく、セクションの開始を示しません。

例外として、最初のセクションにはデータや長さが含まれていません。

各セクション ヘッダーを順番に読み取り、長さを解析してから、次のセクションの読み取りを開始する前に、対応するバイト数をスキップする必要があります。セクション構造に関係なく0xffc0、どころか、 だけを検索することはできません。0xc0

ソース

于 2012-10-28T19:28:22.097 に答える
4

プログラムをどの程度「普遍的」にしたいかによって、考慮すべき問題がいくつかあります。まず、libjpegを使用することをお勧めします。優れた JPEG パーサーは少し厄介な場合がありますが、このライブラリは多くの面倒な作業を行ってくれます。

次に、nm の声明を明確にするために、最初の 0xFFCO ペアが目的の SOF であるという保証はありません。最新のデジタル カメラは、多くの APP0 および APP1 ブロックを含む JPEG ヘッダーをロードするのが好きであることがわかりました。これは、シーケンシャル読み取り中に最初に遭遇する SOF マーカーが、実際には画像のサムネイルである可能性があることを意味します。このサムネイルは通常 JPEG 形式で保存されているため (私が観察した限りでは)、独自の SOF マーカーが装備されています。一部のカメラや画像編集ソフトウェアには、サムネイルよりも大きい (ただし、実際の画像よりは小さい) 画像プレビューが含まれる場合があります。このプレビュー画像は通常 JPEG で、独自の SOF マーカーがあります。画像の SOF マーカーが最後になることは珍しくありません。

最近のほとんどの (すべて?) デジタル カメラは、EXIF タグで画像属性もエンコードします。アプリケーションの要件によっては、これがイメージ サイズを取得する最も簡単で明確な方法である場合があります。EXIF 標準ドキュメントは、EXIF パーサーの作成について知っておくべきことをすべて教えてくれます。( libExifは利用できますが、私のアプリケーションには決して合いません。) とにかく、独自の EXIF を作成したり、ライブラリに依存したりする場合は、EXIF データを検査するための優れたツールがいくつかあります。jheadは非常に優れたツールであり、ExifToolにも恵まれました。

最後に、エンディアンに注意してください。SOF およびその他の標準 JPEG マーカーはビッグエンディアンですが、EXIF マーカーは異なる場合があります。

于 2012-10-29T03:33:35.610 に答える
2

あなたが言及したように、仕様はマーカーが0xFFC0であると述べています。しかし、コードで1バイトしか探していないようですif (b==SOF)

16 進エディタでファイルを開き、0xFFC0 を検索すると、マーカーが見つかります。ファイルの最初の 0xC0 がマーカーである限り、コードは機能します。そうでない場合は、あらゆる種類の未定義の動作が発生します。

最初にファイル全体を読みたいと思います。jpgですよね、どれくらいの大きさですか?(組み込みシステムの場合、これは重要であると考えました) 次に、マーカーの最初の文字を探してステップスルーします。見つかったら、memcmp を使用して、次の 3 バイトが残りの sig と一致するかどうかを確認します。

于 2012-10-28T18:39:49.290 に答える