从任意大小的位图文件中,提取任意区域的图片
接口很简单,就一个 extract() ,用于提取指定区域的图片到 TMemoryStream, 同时生成相应的 bmp 头部。
这个类使用 TFileStream 从原始文件加载位图,所以位图是没有加载到内存的,从而可以快速从大图中提取子图。
unit modelUnit;
interface
uses
Windows, SysUtils, Classes;
type
CBitmapExtract=class
private
fFS: TFileStream;
fBFH: TBitmapFileHeader;
fBIH: TBitmapInfoHeader;
fPadding: Byte;
public
constructor create(const bmp: TFileName);
destructor Destroy; override;
procedure extract(const r: TRect; ms: TMemoryStream);
end;
implementation
{ CBmp }
constructor CBitmapExtract.create(const bmp: TFileName);
begin
fFS:=TFileStream.Create(bmp, fmOpenRead);
fFS.Read(fBFH, SizeOf(fBFH));
fFS.Read(fBIH, SizeOf(fBIH));
fPadding:=fBIH.biWidth*3 mod 4;
if fPadding<>0 then
fPadding:=4-fPadding;
end;
destructor CBitmapExtract.Destroy;
begin
ffs.Free;
inherited;
end;
procedure CBitmapExtract.extract(const r: TRect; ms: TMemoryStream);
var
bfh: TBitmapFileHeader;
bi: TBitmapInfoHeader;
w, h: Integer;
bsPadding: array of Byte;
i: Integer;
begin
Assert(ms<>nil);
w:=r.Right-r.Left+1;
h:=r.Bottom-r.Top+1;
i:=w*3 mod 4;
if i>0 then
SetLength(bsPadding, 4-i);
ms.Clear;
ms.Position:=0;
ZeroMemory(@bfh, SizeOf(bfh));
bfh.bfType:=$4D42;
bfh.bfSize:=SizeOf(bfh) + sizeof(bi) + (w+length(bsPadding))*h*3;
bfh.bfOffBits:=SizeOf(bfh) + sizeof(bi);
ms.Write(bfh, SizeOf(bfh));
ZeroMemory(@bi, SizeOf(bi));
bi.biSize:=SizeOf(bi);
bi.biWidth:=r.Right-r.Left+1;
bi.biHeight:=r.Bottom-r.Top+1;
bi.biPlanes:=1;
bi.biBitCount:=24;
bi.biSizeImage:=(w+length(bsPadding))*h*3;
ms.Write(bi, SizeOf(bi));
for i:=r.Top to r.Bottom do begin
fFs.Position:=fBFH.bfOffBits+(fBIH.biWidth*3+fPadding)*i + r.Left*3;
ms.CopyFrom(fFS, w*3);
if Length(bsPadding)>0 then
ms.Write(bsPadding[0], Length(bsPadding));
end;
end;
end.