A JPEG file consists of pieces whose types are identified by bullets. Piece structure (excluding standalone SOI, EOI, RSTn):
chunk type marker (big-endian FFxx) chunk length (big-endian word) data (length-2 bytes)
Edit: SOS block is limited to a different marker, not length.
Metadata chunks begin with the APPn marker (FFEn), with the exception of the APP0 marker (FFE0) with the JFIF header.
Thus, we can read and compare only significant fragments and ignore the APPn fragments and the COM fragment (as Tlama noted).
Example: hexadecimal representation of some jpeg file:
It starts with the SOI (Image Start) marker FFD8 (stand-alone, no length),
then the part of APP0 (FFE0) with a length = 16 bytes,
then APP1 chunk (FFE1), which contains metadata (EXIF data, NIKON COOLPIX username, etc.), so we can ignore 9053 bytes (23 5D) and check the next block marker at 2373, etc.
Edit: A simple parsing example:
var jp: TMemoryStream; Marker, Len: Word; Position: Integer; PBA: PByteArray; procedure ReadLenAndMovePosition; begin Inc(Position, 2); Len := Swap(PWord(@PBA[Position])^); Inc(Position, Len); end; begin jp := TMemoryStream.Create; jp.LoadFromFile('D:\3.jpg'); Position := 0; PBA := jp.Memory; while (Position < jp.Size - 1) do begin Marker := Swap(PWord(@PBA[Position])^); case Marker of $FFD8: begin Memo1.Lines.Add('Start Of Image'); Inc(Position, 2); end; $FFD9: begin Memo1.Lines.Add('End Of Image'); Inc(Position, 2); end; $FFE0: begin ReadLenAndMovePosition; Memo1.Lines.Add(Format('JFIF Header Len: %d', [Len])); end; $FFE1..$FFEF, $FFFE: begin ReadLenAndMovePosition; Memo1.Lines.Add(Format('APPn or COM Len: %d Ignored', [Len])); end; $FFDA: begin //SOS marker, data stream, ended by another marker except for RSTn Memo1.Lines.Add(Format('SOS data stream started at %d', [Position])); Inc(Position, 2); while Position < jp.Size - 1 do begin if PBA[Position] = $FF then if not (PBA[Position + 1] in [0, $D0..$D7]) then begin Inc(Position, 2); Memo1.Lines.Add(Format('SOS data stream ended at %d', [Position])); Break; end; Inc(Position); end; end; else begin ReadLenAndMovePosition; Memo1.Lines.Add(Format('Marker %x Len: %d Significant', [Marker, Len])); end; end; end; jp.Free; end;