type
TByteArr =
array of Byte;
TJFIFSegment =
packed record
Fix : Byte;
Kind : Byte;
end;
TSOFData =
packed record
SamplePrecision : Byte;
Height : WORD;
// Number of lines
Width : WORD;
// Number of samples per line
Comp : Byte;
// Number of image components in frame
// Data : TByteArr;
end;
PSOFData = ^TSOFData;
// Irgendwo aus dem Netz kopiert..
function ReverseWord(w: word): word;
asm
{$IFDEF CPUX64}
mov rax, rcx
{$ENDIF}
xchg al, ah
end;
function ReadWORD(FS : TFileStream;
out AWord : WORD):boolean;
begin
Result := (FS.
Read(AWord,SizeOf(AWord)) = SizeOf(AWord));
AWord := ReverseWord(AWord);
end;
function ReadSegmentHeader(FS : TFileStream;
out Seg : TJFIFSegment):boolean;
begin
Result := (FS.
Read(Seg,SizeOf(Seg)) = SizeOf(Seg));
end;
function ReadData(FS : TFileStream;
const ALength:WORD;
var Data : TByteArr):boolean;
begin
SetLength(Data, ALength);
Result := (FS.
Read(Data[0],ALength) = ALength);
end;
function GetJPEGImageSize(
const AFileName :
string;
out AHeight, AWidth : integer):boolean;
var
FS : TFileStream;
SOI : WORD;
SEG : TJFIFSegment;
SegSize : WORD;
C0 : PSOFData;
tmpData : TByteArr;
begin
Result := False;
FS := TFileStream.Create(AFileName, fmOpenRead
or fmShareDenyNone);
try
if ReadWORD(FS, SOI)
and (SOI = $FFD8)
then begin // Start Of Image = Magic Bytes zur Erkennung von JPG
While ReadSegmentHeader(FS, SEG)
and (SEG.Fix = $FF)
do begin
if SEG.Kind = $DA
then break;
// Start of Scan = End of Header, danach nur noch Imagedaten
if ReadWORD(FS, SegSize)
then begin
SegSize := SegSize -2;
// Längenangaben um die 2 Byte für die Längenangaben selber reduziert
case SEG.Kind
of
$C0,
// Baseline DCT
$C1,
// Extended sequential DCT, Huffman coding
$C2,
// Progressive DCT, Huffman coding
$C3,
// Lossless (sequential), Huffman coding
$C9,
// Extended sequential DCT, arithmetic coding
$CA,
// Progressive DCT, arithmetic coding
$CB :
// Lossless (sequential), arithmetic coding
begin
// SOFx, im SOF steht am Anfang die Größe des Bildes, anschließend Daten zur Dekodierung
if ReadData(FS, SegSize, tmpData)
then begin
C0 := PSOFData(@tmpData[0]);
AHeight := ReverseWord(C0.Height);
AWidth := ReverseWord(C0.Width);
Result := True;
Break;
end;
end;
else
FS.Position := FS.Position + SegSize;
// Zum nächsten Segment, die weiteren werden nicht gebraucht.
end;
end;
end;
end;
finally
FS.Free;
end;
end;