JPEG画像処理

研究にまるで関係ないけど、今までやったことがない画像処理に2日間研究そっちのけで取り組んでみた。
と言ってもJPEGの仕組みを知るにとどまりましたがw
やろうとしたことは、画像サイズを取得して縮小すること。ということでまずは画像サイズ取得が必要で、JPEGの構造を知る必要がありました。
今回参照にしたのは下記のリンク

JPEG画像形式の概要(フォーマット) - ウェブで用いられる画像形式。
http://siisise.net/jpeg.html

JPEG画像の構造

JPEG画像の情報はセグメントと呼ばれるいくつかのブロック
に分かれており、各セグメントの開始となる2バイトのデータをマーカと呼びます。マーカの1バイト目は0xFFの値となっています。
目的の縦、横の大きさがあるセグメントはSOFというセグメント。マーカが0xFFC0のものを探します。
ここで気を付けるべきは(ここでハマった)、SOFセグメントを見つけるまでに、FFC0の並びが存在しうるということ。
これを回避するための対策は、セグメント中のデータをスキップすること。セグメントのデータサイズはマーカの次の2バイト分に示されているので、それを読み込んでバイト数分スキップ。下記リンク先に詳しいことが載っています

JPEGの縦横サイズ取得について。 - CGI 解決済み| 【OKWAVE】

ソースコード

Cで縦、横を取得して表示するだけのプログラム例を示します。

int main() {
    char* path="test.jpg";
    unsigned char byte[8];
    unsigned char c;
    unsigned int width,height;
    JpgSize(path,&width,&height);
    FILE* file;
    errno_t e  = fopen_s(&file,path,"rb");
    fread(byte,1,2,file); // SOIセグメントを読む
    if(byte[0]!=0xff || byte[1]!=0xd8)
        return-1;

    while(true) {
        fread(byte,1,2,file);
        if(byte[0]==0xff) {  // マーカの確認
            if(byte[1]==0xc0 || byte[1]==0xc2) {   // SOFセグメントならば読み込み
               fread(byte,1,3file); // 3バイト目までは不要
               fread(byte,1,4,file);
               width = ((unsigned int)byte[2]<<8)|byte[3]; // 横
               height = ((unsigned int)byte[0]<<8)|byte[1];  // 縦
               break;
         }
         else { 
               fread(byte,1,2,file); // 他のセグメントデータは読み飛ばす
               unsigned int len = ((unsigned int)byte[0]<<8)|byte[1];
               len-=2; // 長さを表すデータはすでに読んでいる
               while(len>0) {
                    getc(file);
                    len--;
               }
          }
    }
    printf("w:%d h:%d\n",width,height);
    fclose(file);
    return 0;
}

プログラミング言語C 第2版 ANSI規格準拠

プログラミング言語C 第2版 ANSI規格準拠


画像縮小はまた今度。