On 5/30/11, Ben <ben.smith.li...@gmail.com> wrote: > > The reason I'm reading in the jpg files is so I can get their Width and > Height values. Avg. jpeg file sizes are between 35-45KB, and largest > file size is 65KB. > Ben.
A bit off-topic (as to the inner workings of FPImage), but I attached some old code of mine to determine width/height of jpg, gif, bmp, png. It's probably a little faster... Bart
unit PicsLib; { $DEFINE DEBUG} interface uses Windows; function GetBMPSize(const Fn: String; var Width, Height: dword): Boolean; function GetGIFSize(const Fn: String; var Width, Height: dword): Boolean; function GetJPGSize(const Fn: String; var Width, Height: dword): Boolean; function GetPNGSize(const Fn: String; var Width, Height: dword): Boolean; function GetImageSize(const Fn: String; var Width, Height: dword): Boolean; implementation uses SysUtils, Classes; type TBitmapFileHeader = Packed Record ID: word; FileSize: dword; Reserved: dword; BitmapDataOffset: dword; end; TBitmapInfo = Packed Record BitmapHeaderSize: dword; Width: dword; Height: dword; Planes: word; BitsPerPixel: word; Compression: dword; BitmapDataSize: dword; XpelsPerMeter: dword; YPelsPerMeter: dword; ColorsUsed: dword; ColorsImportant: dword; end; TGIFHeader = Packed Record ID: array[0..5] of char; Width, Height: Word; end; TPNGHeader = Packed Record ID: array[0..7] of Char; ChunkLength: dword; ChunkType: array[0..3] of Char; Width: dword; Height: dword; BitsPerPixel: byte; ColorType: byte; Compression: byte; FilterMethod: byte; CRC: dword; end; TJPGHeader = array[0..1] of Byte; //FFD8 = StartOfImage (SOI) (* TJFIFHeader = Packed record //APP0 Header Len: Word; ID: array[0..4] of Char; //JFIF#0 // Maj, Min: Byte; // XYUnits: byte; // XDens, YDens: word; // ThWidth, ThHeight: byte; //Thumbnail info end; *) TSOFHeader = Packed record Len: word; DataPrecision: byte; Height, Width: word; NrComponents: byte; end; function MotorolaToIntelDW(DW: dword): dword; var HiWd, LoWd: word; begin HiWd := HiWord(DW); LoWd := LoWord(DW); HiWd := Swap(HiWd); LoWd := Swap(LoWd); Result := HiWd + (LoWd shl 16); end; function GetImageSize(const Fn: String; var Width, Height: dword): Boolean; begin if AnsiUpperCase(ExtractFileExt(Fn)) = '.BMP' then begin Result := GetBMPSize(Fn, Width, Height); end else if AnsiUpperCase(ExtractFileExt(Fn)) = '.GIF' then begin Result := GetGIFSize(Fn, Width, Height); end else if (AnsiUpperCase(ExtractFileExt(Fn)) = '.JPG') or (AnsiUpperCase(ExtractFileExt(Fn)) = '.JPEG') then begin Result := GetJPGSize(Fn, Width, Height); end else if AnsiUpperCase(ExtractFileExt(Fn)) = '.PNG' then begin Result := GetPNGSize(Fn, Width, Height); end else begin Width := 0; Height := 0; Result := False; end; end; function GetBMPSize(const Fn: String; var Width, Height: dword): Boolean; var BitmapFileHeader: TBitmapFileHeader; BitmapInfo: TBitmapInfo; F: File; bRead: Integer; IDStr: String; begin Result := False; Width := 0; Height := 0; Try AssignFile(F,Fn); FileMode := fmOpenRead or fmShareDenyWrite; Reset(F,1); BlockRead(F,BitmapFileHeader,SizeOf(TBitmapFileHeader),bRead); if bRead <> SizeOf(TBitmapFileHeader) then Raise EInOutError.Create(''); BlockRead(F,BitmapInfo,SizeOf(TBitmapInfo),bRead); if bRead <> SizeOf(TBitmapInfo) then Raise EInOutError.Create(''); CloseFile(F); IDStr := Char(Lo(BitmapFileHeader.ID)) + Char(Hi(BitmapFileHeader.ID)); //Klopt bestandsopmaak ? if (not (IDStr = 'BM') or (IDStr = 'BA')) or (not (BitmapInfo.BitmapHeaderSize in [$28,$0c,$f0])) or (not (BitmapInfo.BitsPerPixel in [1,4,8,16,24,32])) then Exit; Width := BitmapInfo.Width; Height := BitmapInfo.Height; Result := True; Except on EInOutError do begin {$I-} CloseFile(F); InOutRes := 0; //Negeer IO errors hier (mogelijk is bestand al geclosed) Exit; end; end;//try...except end; function GetGIFSize(const Fn: String; var Width, Height: dword): Boolean; var GifHeader: TGIFHeader; F: File; bRead: Integer; begin Result := False; Width := 0; Height := 0; Try AssignFile(F,Fn); FileMode := fmOpenRead or fmShareDenyWrite; Reset(F,1); BlockRead(F,GifHeader,SizeOf(TGIFHeader),bRead); if bRead <> SizeOf(TGIFHeader) then Raise EInOutError.Create(''); CloseFile(F); //Klopt bestandsopmaak ? if not ((AnsiUpperCase(GifHeader.ID) = 'GIF87A') or (AnsiUpperCase(GifHeader.ID) = 'GIF89A')) then Exit; Width := GifHeader.Width; Height := GifHeader.Height; Result := True; Except on EInOutError do begin {$I-} CloseFile(F); InOutRes := 0; //Negeer IO errors hier (mogelijk is bestand al geclosed) Exit; end; end;//try...except end; function GetPNGSize(const Fn: String; var Width, Height: dword): Boolean; var PNGHeader: TPNGHeader; F: File; bRead: Integer; begin Result := False; Width := 0; Height := 0; Try AssignFile(F,Fn); FileMode := fmOpenRead or fmShareDenyWrite; Reset(F,1); BlockRead(F,PNGHeader,SizeOf(TPNGHeader),bRead); if bRead <> SizeOf(TPNGHeader) then Raise EInOutError.Create(''); CloseFile(F); //Klopt bestandsopmaak ? if (AnsiUpperCase(PNGHeader.ID) <> #137'PNG'#13#10#26#10) or (AnsiUpperCase(PNGHeader.ChunkType) <> 'IHDR') then exit; Width := MotorolaToIntelDW(PNGHeader.Width); Height := MotorolaToIntelDW(PNGHeader.Height); Result := true; Except on EInOutError do begin {$I-} CloseFile(F); InOutRes := 0; //Negeer IO errors hier (mogelijk is bestand al geclosed) Exit; end; end;//try...except end; function GetJPGSize(const Fn: String; var Width, Height: dword): Boolean; const Parameterless = [$01, $D0, $D1, $D2, $D3, $D4, $D5, $D6, $D7]; var F: File; bRead: Integer; JPGHeader: TJPGHeader; // JFIFHeader: TJFIFHeader; SOFHeader: TSOFHeader; B, SegType: byte; SegSize: Word; //Thumbnail Size SOF_Found: boolean; Dummy: array[0..65532] of byte; //Max segment length {$IFDEF DEBUG} var tf: text; {$ENDIF} begin {$IFDEF DEBUG} assignfile(tf,'\debug.txt'); if fileexists('\debug.txt') then append(tf) else rewrite(tf); writeln(tf,Fn); {$ENDIF} Result := False; Width := 0; Height := 0; Try AssignFile(F,Fn); FileMode := fmOpenRead or fmShareDenyWrite; Reset(F,1); BlockRead(F,JPGHeader, SizeOf(TJPGHeader),bRead); if bRead <> SizeOf(TJPGHeader) then Raise EInOutError.Create(''); if (JPGHeader[0] <> $FF) or (JPGHeader[1] <> $D8) then begin CloseFile(F); Exit; end; {$IFDEF DEBUG} writeln(tf,'StartOfImage Found'); {$ENDIF} SOF_Found := False; // JFIF_Found := False; //Op zoek naar JFIFF en StartOfFrame (SOF) segment BlockRead(F,B,1,bRead); if bRead <> 1 then Raise EInoutError.Create(''); While (not EOF(F)) and (B = $FF) and not (SOF_Found {and JFIF_Found}) do //Alle segmenten beginnen met $FF begin BlockRead(F,SegType,1,bRead); {$IFDEF DEBUG} write(tf,'Segment Type: '+IntToHex(SegType,2)+' '); {$ENDIF} if bRead <> 1 then Raise EInoutError.Create(''); case SegType of $c0,$c1,$c2 {,$c3,$c5,$c6,$c7,$c9,$ca,$cb,$cd,$ce,$cf ???}: begin//StartOfFrame BlockRead(F,SOFHeader,SizeOf(TSOFHeader),bRead); if bRead <> SizeOf(TSOFHeader) then Raise EInOutError.Create(''); //Motorola -> Intel SOFHeader.Len := Swap(SOFHeader.Len); {$IFDEF DEBUG} write(tf,' Segment Length: '+IntToStr(SOFHeader.Len),' (StartOfFrame)'); {$ENDIF} SOFHeader.Height := Swap(SOFHeader.Height); SOFHeader.Width := Swap(SOFHeader.Width); BlockRead(F,Dummy,SOFHeader.NrComponents*3,bRead); if bRead <> (SOFHeader.NrComponents * 3) then Raise EInOutError.Create(''); Width := SOFHeader.Width; Height := SOFHeader.Height; SOF_Found := true; end; (* //Kennelijk bevat niet ieder JPG een JFIF segmet ... $e0: begin//App0 = JFIF segment BlockRead(F,JFIFHeader,SizeOf(TJFIFHeader),bRead); if bRead <> SizeOf(TJFIFHeader) then Raise EInOutError.Create(''); BytesLeft := Swap(JFIFHeader.Len) - SizeOf(TJFIFHeader); if BytesLeft > 0 then begin BlockRead(F,Dummy,BytesLeft,bRead); if bRead <> BytesLeft then Raise EInOutError.Create(''); end; //Kennelijk bestaan er 2 verschillende APP0 segmenten, //één heeft JFIFF als kenmerk en is 16 bytes + thumbnail groot, //de andere heeft JFXX als kenmerk en is beduidend groter ... if AnsiStrLComp(JFIFHeader.ID,PChar('JF'),2) <> 0 then Break; JFIF_Found := True; end; *) $01, $D0, $D1, $D2, $D3, $D4, $D5, $D6, $D7: begin//Parameterloos segment {$IFDEF DEBUG} write(tf,' Parameterloos'); {$ENDIF} // Negeer end; $d9: begin//EndOfImage {$IFDEF DEBUG} write(tf,' EndOfImage'); {$ENDIF} Break; end; $da: begin//Start Of Scan: JPG Data {$IFDEF DEBUG} write(tf,' StartOfScan'); {$ENDIF} Break; end; else begin//Lees segment in dummy en sla over //De eerste 2 bytes zijn lengte v.h. segment //inclusief de 2 lengte-bytes //Lengtebytes zijn in Motorola formaat (Hi-Lo) BlockRead(F,SegSize,SizeOf(SegSize),bRead); if bRead <> SizeOf(SegSize) then Raise EInOutError.Create(''); SegSize := Swap(SegSize); {$IFDEF DEBUG} write(tf,' Segment Length: '+IntToStr(SegSize)); {$ENDIF} if SegSize > 2 then begin//RLees tot eind van segment SegSize := SegSize - 2; BlockRead(F,Dummy,SegSize,bRead); if bRead <> SegSize then Raise EInOutError.Create(''); end; end; end;//case //Lees volgense segmentbegin, B moet nu $FF zijn ... BlockRead(F,B,1,bRead); if bRead <> 1 then Raise EInoutError.Create(''); {$IFDEF DEBUG} writeln(tf); {$ENDIF} end;//While //Alle info gevonden en opmaak klopt ? if {JFIF_Found and} SOF_Found then Result := True; {$IFDEF DEBUG} writeln(tf);writeln(tf);writeln(tf,' End of Search for markers'); writeln(tf); closefile(tf); {$ENDIF} CloseFile(F); (* if not Result then begin _GetJPGSize(Fn,Width,Height); if (Width <> 0) and (Height <> 0) then Result := true; end; *) Except on EInOutError do begin {$I-} CloseFile(F); InOutRes := 0; //Negeer IO errors hier (mogelijk is bestand al geclosed) Exit; end; end;//try...except end; (* procedure _GetJPGSize(const sFile: string; var wWidth, wHeight: dWord); const ValidSig: array[0..1] of Byte = ($FF, $D8); Parameterless = [$01, $D0, $D1, $D2, $D3, $D4, $D5, $D6, $D7]; var Sig: array[0..1] of byte; f: TFileStream; x: integer; Seg: byte; Dummy: array[0..15] of byte; Len: word; ReadLen: LongInt; function ReadMWord(f: TFileStream): Word; type TMW = record case Byte of 0: (Value: word); 1: (Byte1,Byte2: Byte); end; var mw: TMW; begin f.read(mw.byte2,1); f.read(mw.byte1,1); result := mw.value; end; begin wHeight := 0; wWidth := 0; FillChar(Sig, SizeOf(Sig), #0); f := TFileStream.Create(sFile, fmOpenRead); try ReadLen := f.read(Sig[0], SizeOf(Sig)); for x := Low(Sig) to High(Sig) do if Sig[x] <> ValidSig[x] then ReadLen := 0; if ReadLen > 0 then begin ReadLen := f.read(Seg, 1); while (Seg = $FF) and (ReadLen > 0) do begin ReadLen := f.read(Seg, 1); if Seg <> $FF then begin if (Seg = $C0) or (Seg = $C1) then begin ReadLen := f.read(Dummy[0], 3); { don't need these bytes } wHeight := ReadMWord(f); wWidth := ReadMWord(f); end else begin if not (Seg in Parameterless) then begin Len := ReadMWord(f); f.Seek(Len - 2, 1); f.read(Seg, 1); end else Seg := $FF; { Fake it to keep looping. } end; end; end; end; finally f.Free; end; end; *) end.
_______________________________________________ fpc-pascal maillist - fpc-pascal@lists.freepascal.org http://lists.freepascal.org/mailman/listinfo/fpc-pascal