从任意大小的位图文件中,提取任意区域的图片

接口很简单,就一个 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.
posted @ 2011-09-08 18:45  zzzl  阅读(750)  评论(0编辑  收藏  举报