yunomuのブログ

趣味のこと

JPEGを読む(5) JPEGファイル全体の構造を読めるようにする

 一旦JPEGファイルの全体の構造に立ち戻る。構造のフローチャートはややこしいので一旦飛ばして。Annex E "Encoder and decoder control procedures"のE.2デコードの章を見ていく。

Decode image

 Decoder_setupと、SOF(start of frame)マーカーが出てくるまでマーカーを読む部分("interpret markers")があるけど、これはどちらも読むマーカーの種類は同じなのでまとめてしまっても良さそうに見える。Figure B.16と話が違うような気がしないでもないけど一旦まとめてしまおう。階層の定義(DHP)がある時が考慮されてないけど、これも一旦無視する。そうするとコードはこういうことになる。Decoder#DecodeはFigure E.6のDecode_imageDecoder#decodeMiscは"interpret markers"に相当する。

 Decoder#decodeMiscDecoder#decodeFrameは後で実装する。一旦すべて返却値は無いものとする。

func (d *Decoder) decodeMisc() error {
    // TODO
    return nil
}

func (d *Decoder) decodeFrame() error {
    // TODO
    return nil
}

func (d *Decoder) readSOI() error {
    m, err := d.readMarker()
    if err != nil {
        return err 
    }   

    if m != Marker_SOI {
        slog.Error("readSOI()", "marker", m)
        return ErrUnexpectedToken
    }   

    return nil 
}

func (d *Decoder) Decode() error {
    if err := d.readSOI(); err != nil {
        return err 
    }

    if err := d.decodeMisc(); err != nil {
        return err 
    }

    if err := d.decodeFrame(); err != nil {
        return err 
    }

    return nil 
}

Interpret markers

 Miscにあたる部分はTable E.1に記載してある。

 "merkers"というのはこのなかのいずれかのフィールドのリストらしい。ちなみにフローチャートの"Decoder_setup"の部分で読むテーブルもこの中のDRIやDACらしいので、「まとめてしまっても良さそう」と書いた理由はここにある。ここに挙がっているフィールドは全てマーカーの直後の16ビットでフィールドの長さを示してくれているので、取りあえず中身は読み飛ばしておく。これを繰り返し、Table E.1に記載されていないマーカーがきた場合は読むのをやめる。Markerの方にもそのマーカーがSOFxかどうかを判別するメソッドを足しておく。

import "log/slog"

var frameMarkers = []Marker{
    Marker_SOF0,
    Marker_SOF1,
    Marker_SOF2,
    Marker_SOF3,
    Marker_SOF5,
    Marker_SOF6,
    Marker_SOF7,
    Marker_SOF9,
    Marker_SOF10,
    Marker_SOF11,
    Marker_SOF13,
    Marker_SOF14,
    Marker_SOF15,
}

func (m Marker) isFrameMarker() bool {
    for _, fm := range frameMarkers {
        if m == fm {
            return true
        }
    }
    return false
}

func (d *Decoder) decodeMisc() error {
    for {
        m, err := d.readMarker()
        if err != nil {
            return err
        }

        if m.isFrameMarker() {
            d.unread()
            return nil
        }

        switch m {
        case Marker_DQT, Marker_DHT, Marker_DAC, Marker_DRI, Marker_COM, Marker_APP_n:
            l, err := d.readUint16()
            if err != nil {
                return err
            }

            slog.Info("other header",
                "marker", m,
                "length", l,
            )

            // skip field
            if _, err := d.readBytes(int(l - 2)); err != nil {
                slog.Error("skip")
                return err
            }
        default:
            d.unread()
            return nil
        }
    }
}

Decode frame

 フレームをデコードする。フローチャートはこう。

 これはこのとおりに実装する。Decoder#decodeFrameHeaderDecoder#decodeScanの中身は後回し。

func (d *Decoder) decodeFrameHeader() error {
    // TODO
    return nil
}

func (d *Decoder) decodeScan() error {
    // TODO
    return nil
}

func (d *Decoder) readEOI() error {
    m, err := d.readMarker()
    if err != nil {
        return err
    }

    if m != Marker_EOI {
        slog.Error("readEOI()", "marker", m)
        return ErrUnexpectedMarker
    }

    return nil
}

func (d *Decoder) decodeFrame() error {
    if err := d.readFrameHeader(); err != nil {
        return err
    }

    for {
        if err := d.decodeMisc(); err != nil {
            return err
        }

        m, err := d.readMarker()
        if err != nil {
            return err
        }

        if m != Marker_SOS {
            return ErrUnexpectedMarker
        }

        if err := d.decodeScan(); err != nil {
            return err
        }

        if err := d.readEOI(); err == ErrUnexpectedMarker {
            d.unread()
            continue
        } else if err != nil {
            return err
        }

        return nil
    }
}

 ここまでで一旦ストリームの終端まできた。