Image 如何在Delphi中获取图像文件的尺寸?
在打开图像文件之前,我想知道该文件的宽度和高度 那么,如何做到这一点呢 编辑:Image 如何在Delphi中获取图像文件的尺寸?,image,delphi,dimensions,image-size,Image,Delphi,Dimensions,Image Size,在打开图像文件之前,我想知道该文件的宽度和高度 那么,如何做到这一点呢 编辑: 这指的是jpg、bmp、png和gif类型的图像文件。如果“图像文件”指的是VCL图形系统识别的光栅图像文件,而“打开前”指的是“用户可能注意到文件已打开前”,则可以非常轻松地执行此操作: var pict: TPicture; begin with TOpenDialog.Create(nil) do try if Execute then begin pic
这指的是jpg、bmp、png和gif类型的图像文件。如果“图像文件”指的是VCL图形系统识别的光栅图像文件,而“打开前”指的是“用户可能注意到文件已打开前”,则可以非常轻松地执行此操作:
var
pict: TPicture;
begin
with TOpenDialog.Create(nil) do
try
if Execute then
begin
pict := TPicture.Create;
try
pict.LoadFromFile(FileName);
Caption := Format('%d×%d', [pict.Width, pict.Height])
finally
pict.Free;
end;
end;
finally
Free;
end;
当然,文件是打开的,如果图像很大,则需要大量内存。但是,如果您需要在不加载文件的情况下获取metatada(如维度),我相信您需要一个更“复杂”的解决方案。您可以尝试第页。我还没有测试过它,但它似乎可以正常工作
此外,不同的文件类型有不同的方式来获取宽度和高度。在你的问题上尽量说得更具体些
其中一个页面anwser:
unit ImgSize;
interface
uses Classes;
procedure GetJPGSize(const sFile: string; var wWidth, wHeight: word);
procedure GetPNGSize(const sFile: string; var wWidth, wHeight: word);
procedure GetGIFSize(const sGIFFile: string; var wWidth, wHeight: word);
implementation
uses SysUtils;
function ReadMWord(f: TFileStream): word;
type
TMotorolaWord = record
case byte of
0: (Value: word);
1: (Byte1, Byte2: byte);
end;
var
MW: TMotorolaWord;
begin
// It would probably be better to just read these two bytes in normally and
// then do a small ASM routine to swap them. But we aren't talking about
// reading entire files, so I doubt the performance gain would be worth the trouble.
f.Read(MW.Byte2, SizeOf(Byte));
f.Read(MW.Byte1, SizeOf(Byte));
Result := MW.Value;
end;
procedure GetJPGSize(const sFile: string; var wWidth, wHeight: word);
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;
begin
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;
procedure GetPNGSize(const sFile: string; var wWidth, wHeight: word);
type
TPNGSig = array[0..7] of byte;
const
ValidSig: TPNGSig = (137, 80, 78, 71, 13, 10, 26, 10);
var
Sig: TPNGSig;
f: tFileStream;
x: integer;
begin
FillChar(Sig, SizeOf(Sig), #0);
f := TFileStream.Create(sFile, fmOpenRead);
try
f.Read(Sig[0], SizeOf(Sig));
for x := Low(Sig) to High(Sig) do
if Sig[x] <> ValidSig[x] then
exit;
f.Seek(18, 0);
wWidth := ReadMWord(f);
f.Seek(22, 0);
wHeight := ReadMWord(f);
finally
f.Free;
end;
end;
procedure GetGIFSize(const sGIFFile: string; var wWidth, wHeight: word);
type
TGIFHeader = record
Sig: array[0..5] of char;
ScreenWidth, ScreenHeight: word;
Flags, Background, Aspect: byte;
end;
TGIFImageBlock = record
Left, Top, Width, Height: word;
Flags: byte;
end;
var
f: file;
Header: TGifHeader;
ImageBlock: TGifImageBlock;
nResult: integer;
x: integer;
c: char;
DimensionsFound: boolean;
begin
wWidth := 0;
wHeight := 0;
if sGifFile = '' then
exit;
{$I-}
FileMode := 0; // read-only
AssignFile(f, sGifFile);
reset(f, 1);
if IOResult <> 0 then
// Could not open file
exit;
// Read header and ensure valid file
BlockRead(f, Header, SizeOf(TGifHeader), nResult);
if (nResult <> SizeOf(TGifHeader)) or (IOResult <> 0)
or (StrLComp('GIF', Header.Sig, 3) <> 0) then
begin
// Image file invalid
close(f);
exit;
end;
// Skip color map, if there is one
if (Header.Flags and $80) > 0 then
begin
x := 3 * (1 SHL ((Header.Flags and 7) + 1));
Seek(f, x);
if IOResult <> 0 then
begin
// Color map thrashed
close(f);
exit;
end;
end;
DimensionsFound := False;
FillChar(ImageBlock, SizeOf(TGIFImageBlock), #0);
// Step through blocks
BlockRead(f, c, 1, nResult);
while (not EOF(f)) and (not DimensionsFound) do
begin
case c of
',': // Found image
begin
BlockRead(f, ImageBlock, SizeOf(TGIFImageBlock), nResult);
if nResult <> SizeOf(TGIFImageBlock) then
begin
// Invalid image block encountered
close(f);
exit;
end;
wWidth := ImageBlock.Width;
wHeight := ImageBlock.Height;
DimensionsFound := True;
end;
',' : // Skip
begin
// NOP
end;
// nothing else, just ignore
end;
BlockRead(f, c, 1, nResult);
end;
close(f);
{$I+}
end;
end.
unitimgsize;
接口
使用类;
过程GetJPGSize(const-sFile:string;var-wWidth,wHeight:word);
过程GetPNGSize(const-sFile:string;var-wWidth,wHeight:word);
过程GetGIFSize(const sGIFFile:string;var wWidth,wHeight:word);
实施
使用SysUtils;
函数ReadMWord(f:TFileStream):word;
类型
TMotorolaWord=记录
大小写字节
0:(值:word);
1:(字节1,字节2:字节);
结束;
变量
MW:TMotorolaWord;
开始
//最好是在正常情况下和正常情况下读取这两个字节
//然后执行一个小的ASM例程来交换它们。但我们不是在谈论
//读取整个文件,因此我怀疑性能提升是否值得费心。
f、 读取(MW.Byte2,SizeOf(Byte));
f、 读取(MW.Byte1,SizeOf(Byte));
结果:=分子量值;
结束;
过程GetJPGSize(const-sFile:string;var-wWidth,wHeight:word);
常数
ValidSig:字节=($FF,$D8)的数组[0..1];
无参数=[$01、$D0、$D1、$D2、$D3、$D4、$D5、$D6、$D7];
变量
Sig:字节的数组[0..1];
f:TFileStream;
x:整数;
Seg:字节;
虚拟:字节的数组[0..15];
蓝:字;
雷德伦:朗吉特;
开始
FillChar(Sig,SizeOf(Sig),#0);
f:=TFileStream.Create(sFile,fmOpenRead);
尝试
ReadLen:=f.Read(Sig[0],SizeOf(Sig));
对于x:=低(Sig)至高(Sig)do
如果Sig[x]有效,则
ReadLen:=0;
如果ReadLen>0,则
开始
ReadLen:=f.Read(Seg,1);
而(Seg=$FF)和(ReadLen>0)则
开始
ReadLen:=f.Read(Seg,1);
如果Seg$FF,则
开始
如果(Seg=$C0)或(Seg=$C1),则
开始
ReadLen:=f.Read(伪[0],3);//不需要这些字节
wHeight:=ReadMWord(f);
wWidth:=ReadMWord(f);
结束
其他的
开始
如果不是(Seg in Parameterless),则
开始
Len:=ReadMWord(f);
f、 搜索(Len-2,1);
f、 读取(Seg,1);
结束
其他的
Seg:=$FF;//假装它继续循环。
结束;
结束;
结束;
结束;
最后
f、 免费的;
结束;
结束;
过程GetPNGSize(const-sFile:string;var-wWidth,wHeight:word);
类型
TPNGSig=字节数组[0..7];
常数
ValidSig:TPNGSig=(137,80,78,71,13,10,26,10);
变量
Sig:TPNGSig;
f:tFileStream;
x:整数;
开始
FillChar(Sig,SizeOf(Sig),#0);
f:=TFileStream.Create(sFile,fmOpenRead);
尝试
f、 读取(Sig[0],SizeOf(Sig));
对于x:=低(Sig)至高(Sig)do
如果Sig[x]有效,则
出口
f、 寻求(18,0);
wWidth:=ReadMWord(f);
f、 寻求(22,0);
wHeight:=ReadMWord(f);
最后
f、 免费的;
结束;
结束;
过程GetGIFSize(const sGIFFile:string;var wWidth,wHeight:word);
类型
TGIFHeader=记录
Sig:char的数组[0..5];
屏幕宽度、屏幕高度:字;
标志、背景、方面:字节;
结束;
TGIFImageBlock=记录
左、上、宽、高:字;
标志:字节;
结束;
变量
f:文件;
标题:TGifHeader;
ImageBlock:TGifImageBlock;
结果:整数;
x:整数;
c:半焦;
维度查找:布尔值;
开始
wWidth:=0;
当:=0;
如果sGifFile='',则
出口
{$I-}
文件模式:=0;//只读
赋值文件(f,sGifFile);
复位(f,1);
如果结果为0,则
//无法打开文件
出口
//读取头并确保文件有效
区块读取(f,标头,SizeOf(TGifHeader),nResult);
如果(nResult SizeOf(TGifHeader))或(IOResult 0)
或者(StrLComp('GIF',Header.Sig,3)0)然后
开始
//图像文件无效
关闭(f);
出口
结束;
//跳过颜色贴图(如果有)
如果(Header.Flags和$80)>0,则
开始
x:=3*(1个SHL((Header.Flags和7)+1));
寻找(f,x);
如果结果为0,则
开始
//彩色地图
关闭(f);
出口
结束;
结束;
维度发现:=假;
FillChar(ImageBlock,SizeOf(TGIFImageBlock),#0);
//跨过街区
区块读取(f,c,1,nResult);
而(非EOF(f))和(非尺寸基金)则
开始
案例c
“,”://找到图像
开始
BlockRead(f,ImageBlock,SizeOf(TGIFImageBlock),nResult);
如果nResult SizeOf(TGIFImageBlock),则
开始
//遇到无效的图像块
关闭(f);
出口
结束;
wWidth:=ImageBlock.Width;
wHeight:=图像块高度;
维度发现:=真;
结束;
“,”://跳过
开始
//不
结束;
//没有别的,只是忽略
结束;
区块读取(f,c,1,nResult);
结束;
关闭(f);
{$I+}
结束;
结束。
对于BMP(也可以在我提到的页面上找到):
函数FetchBitmapHeader(PictFileName:String;Var-wd,ht:Word):布尔值;
//类似的例程在“位图区域”例程中
标识出口;
常数
ValidSig:字节=($FF,$D8)的数组[0..1];
无参数=[$01、$D0、$D1、$D2、$D3、$D4、$D5、$D6、$D7];
BmpSig=4d42美元;
变量
//错误:布尔;
fh:HFile;
//tof:TOFSTRUCT;
bf:TBITMAPFIL
function FetchBitmapHeader(PictFileName: String; Var wd, ht: Word): Boolean;
// similar routine is in "BitmapRegion" routine
label ErrExit;
const
ValidSig: array[0..1] of byte = ($FF, $D8);
Parameterless = [$01, $D0, $D1, $D2, $D3, $D4, $D5, $D6, $D7];
BmpSig = $4d42;
var
// Err : Boolean;
fh: HFile;
// tof : TOFSTRUCT;
bf: TBITMAPFILEHEADER;
bh: TBITMAPINFOHEADER;
// JpgImg : TJPEGImage;
Itype: Smallint;
Sig: array[0..1] of byte;
x: integer;
Seg: byte;
Dummy: array[0..15] of byte;
skipLen: word;
OkBmp, Readgood: Boolean;
begin
// Open the file and get a handle to it's BITMAPINFO
OkBmp := False;
Itype := ImageType(PictFileName);
fh := CreateFile(PChar(PictFileName), GENERIC_READ, FILE_SHARE_READ, Nil,
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
if (fh = INVALID_HANDLE_VALUE) then
goto ErrExit;
if Itype = 1 then
begin
// read the BITMAPFILEHEADER
if not GoodFileRead(fh, @bf, sizeof(bf)) then
goto ErrExit;
if (bf.bfType <> BmpSig) then // 'BM'
goto ErrExit;
if not GoodFileRead(fh, @bh, sizeof(bh)) then
goto ErrExit;
// for now, don't even deal with CORE headers
if (bh.biSize = sizeof(TBITMAPCOREHEADER)) then
goto ErrExit;
wd := bh.biWidth;
ht := bh.biheight;
OkBmp := True;
end
else
if (Itype = 2) then
begin
FillChar(Sig, SizeOf(Sig), #0);
if not GoodFileRead(fh, @Sig[0], sizeof(Sig)) then
goto ErrExit;
for x := Low(Sig) to High(Sig) do
if Sig[x] <> ValidSig[x] then
goto ErrExit;
Readgood := GoodFileRead(fh, @Seg, sizeof(Seg));
while (Seg = $FF) and Readgood do
begin
Readgood := GoodFileRead(fh, @Seg, sizeof(Seg));
if Seg <> $FF then
begin
if (Seg = $C0) or (Seg = $C1) or (Seg = $C2) then
begin
Readgood := GoodFileRead(fh, @Dummy[0],3); // don't need these bytes
if ReadMWord(fh, ht) and ReadMWord(fh, wd) then
OkBmp := True;
end
else
begin
if not (Seg in Parameterless) then
begin
ReadMWord(fh,skipLen);
SetFilePointer(fh, skipLen - 2, nil, FILE_CURRENT);
GoodFileRead(fh, @Seg, sizeof(Seg));
end
else
Seg := $FF; // Fake it to keep looping
end;
end;
end;
end;
ErrExit: CloseHandle(fh);
Result := OkBmp;
end;
function GetBitmapDimensions(const FileName: string; out Width,
Height: integer): boolean;
const
BMP_MAGIC_WORD = ord('M') shl 8 or ord('B');
var
f: TFileStream;
header: TBitmapFileHeader;
info: TBitmapInfoHeader;
begin
result := false;
f := TFileStream.Create(FileName, fmOpenRead);
try
if f.Read(header, sizeof(header)) <> sizeof(header) then Exit;
if header.bfType <> BMP_MAGIC_WORD then Exit;
if f.Read(info, sizeof(info)) <> sizeof(info) then Exit;
Width := info.biWidth;
Height := abs(info.biHeight);
result := true;
finally
f.Free;
end;
end;
Uses ..., GraphicEx,...,...;
Procedure ReadTifSize (FN:String; Var iWidth,iHeight:Integer);
Var FS:TFileStream;
TIFF:TTIFFGraphic;
Begin
iWidth:=0;iHeight:=0;
TIFF:=TTIFFGraphic.Create;
FS:=TFileStream.Create(FN,OF_READ);
Try
TIFF.ReadImageProperties(FS,0);
iWidth:=TIFF.ImageProperties.Width;
iHeight:=TIFF.ImageProperties.Height;
Finally
TIFF.Destroy;
FS.Free;
End;
End;
function GetGifSize(var Stream: TMemoryStream; var Width: Word; var Height: Word): Boolean;
var
HeaderStr: AnsiString;
begin
Result := False;
Width := 0;
Height := 0;
//GIF header is 13 bytes in length
if Stream.Size > 13 then
begin
SetString(HeaderStr, PAnsiChar(Stream.Memory), 6);
if (HeaderStr = 'GIF89a') or (HeaderStr = 'GIF87a') then
begin
Stream.Seek(6, soFromBeginning);
Stream.Read(Width, 2); //Width is located at bytes 7-8
Stream.Read(Height, 2); //Height is located at bytes 9-10
Result := True;
end;
end;
end;
procedure GetJPGSize(const Filename: string; var ImgWidth, ImgHeight: word);
const
SigJPG : TBytes = [$FF, $D8];
SigC01 : TBytes = [$FF, $C0];
SigC02 : TBytes = [$FF, $C1];
var
FStream: TFileStream;
Buf: array[0..1] of Byte;
Offset,CheckMarker : Word;
//--------------------------------------------------------------------------------------------------------------------------------------------------------------
function SameValue(Sig:TBytes):Boolean;
begin
Result := CompareMem(@Sig[0], @Buf[0], Length(Sig));
end;
//--------------------------------------------------------------------------------------------------------------------------------------------------------------
function CheckMarkerOrVal(var Value:Word):Boolean;
begin
FStream.ReadData(Buf, Length(Buf));
Value := Swap(PWord(@Buf[0])^);
Result := (Buf[0] = $FF);
end;
//--------------------------------------------------------------------------------------------------------------------------------------------------------------
begin
FStream := TFileStream.Create(Filename, fmOpenRead);
Try
// First two bytes in a JPG file MUST be $FFD8, followed by the next marker
If not (CheckMarkerOrVal(CheckMarker) and SameValue(SigJPG))
then exit;
Repeat
If not CheckMarkerOrVal(CheckMarker)
then exit;
If SameValue(SigC01) or SameValue(SigC02) then begin
FStream.Position := FStream.Position + 3;
CheckMarkerOrVal(ImgHeight);
CheckMarkerOrVal(ImgWidth);
exit;
end;
CheckMarkerOrVal(Offset);
FStream.Position := FStream.Position + Offset - 2;
until FStream.Position > FStream.Size div 2;
Finally
FStream.Free;
end;
end;