读书人

GetPixel的速度太慢了请教怎么用Get

发布时间: 2012-03-05 11:54:03 作者: rapoo

GetPixel的速度太慢了,请问如何用GetDIBits解决这个问题?
声明:不想用TBitmap,务必用GetDIBits解决,怎么搞?(也就是说只想用API搞定)

一下这段代码是我自己写的,对屏幕的每个点进行扫描。速度非常慢!!
即使把ListBox1.items.add(inttostr(Pix));注释掉,也要1分半钟左右,才能扫描完。
本人机器酷睿双核,4G内存,配置算是很不错了,还这么慢,怎么办?
procedure TForm1.Button1Click(Sender: TObject);
var
X, Y: integer;
iX, iY: integer;
pix: DWORD;
DC: HDC;
begin
DC := GetDC(0);
X := GetSystemMetrics(SM_CXSCREEN); //得到屏幕的宽度
Y := GetSystemMetrics(SM_CYSCREEN); //得到屏幕的高度
for iY := 4 to Y do //高度
for iX := 1 to X do //宽度
begin
Pix := Windows.GetPixel(DC, iX, iY);
ListBox1.items.add(inttostr(Pix)); //输入每个像素点的颜色值
end;
Windows.ReleaseDC(0, DC);
end;

///////////////////////// 这里是重点了 /////////////////////////
查了资料后,才知道可以用GetDIBits这个API,但是用起来好复杂,
找到了C代码后,将它翻译成了Delphi代码,却不知道怎么将lpBuf里面的每个像素点输出了。
研究了整整2天,能查到的资料也非常少,跪求高手解决,300相送。

procedure TForm1.Button6Click(Sender: TObject);
const
HEAP_ZERO_MEMORY = $8;
var
b: BITMAPINFO;
bb: bitmap;
lpBuf: array of byte;
_hbitmap, hold: hbitmap;
_hdc, _hcdc: hdc;
hp: thandle;
dwx, dwy: dword;
begin
dwX := GetSystemMetrics(SM_CXSCREEN);
dwY := GetSystemMetrics(SM_CYSCREEN);
_hDC := GetDC(0);
_hcDC := CreateCompatibleDC(_hDC);
_hBitmap := CreateCompatibleBitmap(_hDC, dwX, dwY);
hOld := SelectObject(_hcDC, _hBitmap);

BitBlt(_hcDC, 0, 0, dwX, dwY, _hDC, 0, 0, SRCCOPY);

bb.bmWidth := dwX;
bb.bmHeight := dwY;
bb.bmPlanes := 1;
bb.bmWidthBytes := bb.bmWidth * 3;
bb.bmBitsPixel := 3;
bb.bmType := 0;

b.bmiHeader.biSize := sizeof(BITMAPINFOHEADER);
b.bmiHeader.biWidth := dwX;
b.bmiHeader.biHeight := dwY;
b.bmiHeader.biPlanes := 1;
b.bmiHeader.biBitCount := 24;
b.bmiHeader.biCompression := BI_RGB;
b.bmiHeader.biSizeImage := 0;
b.bmiHeader.biXPelsPerMeter := 0;
b.bmiHeader.biYPelsPerMeter := 0;
b.bmiHeader.biClrUsed := 0;
b.bmiHeader.biClrImportant := 0;
b.bmiColors[0].rgbBlue := 8;
b.bmiColors[0].rgbGreen := 8;
b.bmiColors[0].rgbRed := 8;
b.bmiColors[0].rgbReserved := 0;
hp := GetProcessHeap;

lpBuf := HeapAlloc(hp, HEAP_ZERO_MEMORY, bb.bmHeight * bb.bmWidth * 4);
GetDIBits(_hcDC, _hBitmap, 0, dwY, lpBuf, b, DIB_RGB_COLORS);

for x := 1 to dwX do //////////// 这里到底应该怎么输入每个像素点的颜色值啊???
for y := 1 to dwY do /// 难道是我的代码没翻译好?????????
ListBox1.Items.Add(lpBuf[x, y]); //输入每个像素点的颜色


ReleaseDC(0, _hDC);
DeleteDC(_hcDC);
DeleteObject(_hBitmap);
DeleteObject(hOld);
HeapFree(hp, 0, lpBuf);
end;

///////////////////////// 这里是重点了 /////////////////////////
查了资料后,才知道可以用GetDIBits这个API,但是用起来好复杂,
找到了C代码后,将它翻译成了Delphi代码,却不知道怎么将lpBuf里面的每个像素点输出了。
研究了整整2天,能查到的资料也非常少,跪求高手解决。
声明:不想用TBitmap,务必用GetDIBits解决,怎么搞?

[解决办法]

Delphi(Pascal) code
var  saveBitmap, Bitmap: HBITMAP;  memDC: HDC;  DC: HDC;  bmi: TBitmapInfo;  Buf: Pointer;  p: PRGBTriple;  Stride, Offset: Integer;  x, y: Integer;  w, h: Integer;begin  w := GetSystemMetrics(SM_CXSCREEN);   h := GetSystemMetrics(SM_CYSCREEN);  Stride := ((w * 24 + 31) and $ffffffe0) shr 3;  GetMem(Buf, h * Stride);  try    DC := GetDC(0);    Bitmap := CreateCompatibleBitmap(DC, w, h);    try      memDC := CreateCompatibleDC(DC);      saveBitmap := SelectObject(memDC, Bitmap);      try        BitBlt(memDC, 0, 0, w, h, DC, 0, 0, SRCCOPY);      finally        SelectObject(memDC, saveBitmap);        DeleteDC(memDC);      end;      bmi.bmiHeader.biSize := Sizeof(TBitmapInfoHeader);      bmi.bmiHeader.biWidth := w;      bmi.bmiHeader.biHeight := h;      bmi.bmiHeader.biPlanes := 1;      bmi.bmiHeader.biBitCount := 24;      bmi.bmiHeader.biCompression := BI_RGB;      GetDIBits(DC, Bitmap, 0, h, Buf, bmi, DIB_RGB_COLORS);    finally      DeleteObject(Bitmap);      ReleaseDC(0, DC);    end;  // 因为屏幕像素点数量在100万以上,下面这段代码可能造成程序没反应,如果要用这段代码测试一下,可把前面的w,h分别改为100{    Offset := Stride - bmi.bmiHeader.biWidth * 3;    p := Buf;    for y := 1 to h do    begin      for x := 1 to w do      begin         ListBox1.Items.Add(IntToStr(RGB(p^.rgbtRed, p^.rgbtGreen, p^.rgbtBlue)));         Inc(p);      end;      Inc(Integer(p), Offset);    end;}  finally    FreeMem(Buf);  end;end; 

读书人网 >.NET

热点推荐