ScreenGrabber is a part of Breeze (also licenced as freeware GNU GPL).
You can find full source code on my web pages. Now I'm implementing 2
way feed-back-buffer to accelerate and minimize data traffic.
1. call method Grab to find minimal changed rectangle (on the screen).
2. call GrabAccept.
3. in ResultBMP is stored changed bitmapdata.
ScreenGrabber is developed in C++ and Object Pascal. Pascal for graphics
issues, C++ for robust logic.
Source code:
unit ScreenChangeRecognition;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls, ExtCtrls,Math;
type
TPixels = array[0..$FFFFFF] of dword;
PPixels = ^TPixels;
type
TChangeResult = record
result:boolean; //byly detekovany zmeny
ChangeRect:TRect; //obdelnik ktery se vymenil
KeyFrame:boolean; //zjisti jestli byl zmenen celyscreen
end;
type
TGrabMode = (GM_NORMAL,GM_KEYFRAME,GM_NOTRAYWND);
type
TChangeRecognition = class
private
ScreenDC:HDC;
bmp:array [0..1] of TBitmap;
pixels:array [0..1] of PPixels; //pole pixelu pro kazdou bitmapu
lowbmp:TBitmap; //slouzi pro ulozeni rozdilu
lowpix:PPixels; //pixely bitmapy pro detekci zmen
counter:dword; //pocita kolikrat bylo zavolano grab
fVideoHeight: integer;
fVideoWidth: integer;
fVideoX: integer;
fVideoY: integer;
fVideoH: integer;
fVideoW: integer;
RectSize:integer;
fGrabMode: TGrabMode;
procedure setVideoHeight(const Value: integer);
procedure setVideoWidth(const Value: integer);
procedure setVideoX(const Value: integer);
procedure setVideoY(const Value: integer);
procedure setVideoH(const Value: integer);
procedure setVideoW(const Value: integer);
public
LastResult:TChangeResult;
ResultBMP:TBitmap; //bitmapa se zmenenou casti
procedure Grab; //najde zmeny v obrazu
procedure GrabAccept; //akceptuje zmeny
function getBitmap:TBitmap;
function getLowBMP:TBitmap;
constructor create;
destructor destroy;
procedure setVideoRect(ax,ay,aw,ah,destw,desth:integer);
property VideoX:integer read fVideoX write setVideoX;
property VideoY:integer read fVideoY write setVideoY;
property VideoW:integer read fVideoW write setVideoW;
property VideoH:integer read fVideoH write setVideoH;
property VideoWidth:integer read fVideoWidth write setVideoWidth;
property VideoHeight:integer read fVideoHeight write setVideoHeight;
property GrabMode:TGrabMode read fGrabMode write fGrabMode;
end;
implementation
{ TChangeRecognition }
constructor TChangeRecognition.create;
var a:integer;
begin
//zjisti device context obrazovky
ScreenDC:=getDC(0);
RectSize:=5;
//nastavi sirku a vysku videa
fVideoWidth:=screen.width;
fVideoHeight:=screen.Height;
fVideoW:=screen.width;
fVideoH:=screen.height;
fGrabMode:=GM_NORMAL;
//vytvori bitmapy do nichz bude uklada screen
for a:=0 to high(bmp) do
begin
bmp[a]:=TBitmap.create;
bmp[a].Width:=VideoWidth;
bmp[a].Height:=VideoHeight;
bmp[a].PixelFormat:=pf32bit;
//nacte ukazatel
pixels[a]:=bmp[a].ScanLine[bmp[a].height-1];
end;
ResultBMP:=TBitmap.create;
ResultBMP.PixelFormat:=pf32bit;
//nastavi rozmery lowbitmapy pro detekci rozdilu
lowbmp:=TBitmap.create;
//bitmapa musi byt vetsi o 3 pixely nebot se predsazuje pixel
//dopredu a 2 pixely dozadu
lowbmp.Width:=trunc(bmp[0].Width/RectSize)+3;
lowbmp.Height:=trunc(bmp[0].Height/RectSize)+3;
lowbmp.PixelFormat:=pf32bit;
//nacte pixely
lowpix:=lowbmp.ScanLine[lowbmp.height-1];
end;
destructor TChangeRecognition.destroy;
begin
end;
//nastavi vysky videa
function TChangeRecognition.getBitmap: TBitmap;
var whichBMP:integer;
begin
whichBMP:=(counter mod (high(bmp)+1));
result:=bmp[whichBMP];
result:=bmp[0];
end;
function TChangeRecognition.getLowBMP: TBitmap;
begin
result:=lowbmp
end;
procedure TChangeRecognition.grab;
var whichBMP:integer; //ktera bitmapa se pouzije
x,y:integer;
startx,starty:integer; //startovaci pozice aby bylo mozne detekovat
zmeny
position:integer; //pozice v poli pixelu ktera se porovnava
pix1,pix2:PPixels; //pole pixelu pro porovnani a detekci zmen
xscale,yscale:single; //koeficienty roztazeni okna
TrayWnd:hwnd; //okno jehoz zmeny se nezaznamenavaji
TrayWndRect:TRect;
begin
counter:=counter+1;
//zjisti do ktere bitmapy se bude tisknout tentokrat
whichBMP:=(counter mod (high(bmp)+1));
whichBMP:=1;
//pokud jsou strany obdelniku a,b source a dest stejne tak provede bitblt
if ((VideoW=VideoWidth) and (VideoH=VideoHeight)) then
begin
bitblt(bmp[whichBMP].Canvas.Handle,
0,0,bmp[whichBMP].Width,bmp[whichBMP].Height,
ScreenDC,VideoX,VideoY,srccopy);
end
//jinak provede stretchblt
else
begin
SetStretchBltMode(bmp[whichBMP].Canvas.Handle,HALFTONE);
//zmensi bitmapu
StretchBlt(bmp[whichBMP].Canvas.Handle,
0,0,bmp[whichBMP].Width,bmp[whichBMP].Height,
ScreenDC,VideoX,VideoY,VideoW,VideoH,srccopy);
end;
//pokud je snimek klicovym obrazkem tak neni treba vypocitavat
nejmensi obdelnik
if GrabMode=GM_KEYFRAME then
begin
LastResult.result:=true;
LastResult.ChangeRect:=rect(0,0,VideoWidth,VideoHeight);
LastResult.KeyFrame:=true;
exit;
end;
//zjisti handle traywnd
TrayWnd:=FindWindow('Shell_TrayWnd',nil);
if not(getwindowrect(TrayWnd,TrayWndRect)) then
TrayWndRect:=rect(0,0,0,0);
//zjisti koeficient roztazeni z puvodni oblasti do nove
xscale:=(VideoW)/VideoWidth;
yscale:=(VideoH)/VideoHeight;
//resetuje posledni vysledek
LastResult.result:=false;
LastResult.ChangeRect:=rect($FFFF,$FFFF,-1,-1);
LastResult.KeyFrame:=false;
//premaze lowbmp
zeromemory(@lowpix[0],lowbmp.width*lowbmp.height*sizeof(dword));
//v pix1 je ulozena aktualni mapa v pix2 stara podle niz se porovnava
pix1:=pixels[whichBMP];
pix2:=pixels[abs(whichBMP-1)];
//urci startovni pozice x a y
startx:=counter mod RectSize;
starty:=trunc(counter/RectSize) mod RectSize;
//prohleda zmeny v obrazku
//nastavi y na pocatek
y:=starty;
while y<VideoHeight do
begin
//nastavi x na pocatek
x:=startx;
while x<VideoWidth do
begin
//zjisti jestli se na dotycnem miste nenachazi traywnd
if GrabMode=GM_NOTRAYWND then
if ptinrect(TrayWndRect,point(trunc(x*xscale),
trunc((VideoHeight-y)*yscale))) then
begin
x:=x+RectSize;
continue;
end;
//v ramci na hodnote counter systematicky prochazi obrazovku
//pokud je steprect 8 a obraz se scanuje 4 krat za vterinu
//je stredni doba nalezeni zmeny pixelu 8 vterin
position:=y*VideoWidth+x;
if(pix1[position]<>pix2[position]) then
with LastResult do
begin
result:=true;
//upravi minimalni obdelnik ve kterem doslo ke zmenam
ChangeRect:=rect(min(ChangeRect.Left,x-RectSize),
min(ChangeRect.Top,y-RectSize),
max(ChangeRect.Right,x+RectSize),
max(ChangeRect.Bottom,y+RectSize));
//zmeni pixel v lowbmp
//pozor x je ve skutecnosti x-1 nebot lowbmp je predsazena
//lowpix[y*lowbmp.Width+x]:=$000000FF;
//lowpix[y*lowbmp.Width+x+1]:=$000000FF;
//lowpix[y*lowbmp.Width+x+2]:=$000000FF;
//lowpix[(y+1)*lowbmp.Width+x+2]:=$000000FF;
//lowpix[(y+2)*lowbmp.Width+x+2]:=$000000FF;
end;
//inkrementuje x
x:=x+RectSize;
end;
//inkrementuje y
y:=y+RectSize;
end;
//vysledny obdelnik je jeste treba upravit
if LastResult.result then
with LastResult do
begin
{//zameni souradnice tak aby byl pocatek vlevo nahore
ChangeRect:=rect(VideoX+ChangeRect.Left,VideoY+VideoHeight-ChangeRect.Bottom,
VideoX+ChangeRect.Right,VideoY+VideoHeight-ChangeRect.Top);
//upravi obdelnik aby se vesel do vyrezu obrazku
ChangeRect:=rect(max(ChangeRect.Left,VideoX),
max(ChangeRect.Top,VideoY),
min(ChangeRect.Right,VideoX+VideoWidth),
min(ChangeRect.Bottom,VideoY+VideoHeight));}
//zameni souradnice tak aby byl pocatek vlevo nahore
ChangeRect:=rect(ChangeRect.Left,VideoHeight-ChangeRect.Bottom,
ChangeRect.Right,VideoHeight-ChangeRect.Top);
//upravi obdelnik aby se vesel do vyrezu obrazku
ChangeRect:=rect(max(ChangeRect.Left,0),
max(ChangeRect.Top,0),
min(ChangeRect.Right,VideoWidth),
min(ChangeRect.Bottom,VideoHeight));
end;
end;
procedure TChangeRecognition.GrabAccept;
begin
//pokud je vysledek grab kladny je volana metoda grabaccept
//ktera detekuje bitmapu jez se zmenila
if LastResult.result then
begin
//zjisti velikost ResultBMP
ResultBMP.width:=LastResult.ChangeRect.Right-LastResult.ChangeRect.Left;
ResultBMP.Height:=LastResult.ChangeRect.Bottom-LastResult.ChangeRect.Top;
//zjisti bitmapu vysledku
bitblt(ResultBMP.Canvas.Handle,0,0,ResultBMP.Width,ResultBMP.Height,
bmp[1].canvas.handle,
LastResult.ChangeRect.Left,LastResult.ChangeRect.Top,srccopy);
//ulozi zmenenou cast do bmp1
bitblt(bmp[0].Canvas.Handle,
LastResult.ChangeRect.Left,LastResult.ChangeRect.Top,
ResultBMP.width,ResultBMP.height,
ResultBMP.canvas.handle,0,0,srccopy);
end;
end;
procedure TChangeRecognition.setVideoH(const Value: integer);
begin
fVideoH := min(screen.Height,Value);
end;
procedure TChangeRecognition.setVideoHeight(const Value: integer);
var a:integer;
begin
//nastavi vysku videa
fVideoHeight := min(screen.Height,max(Value,1));
//zmeni rozliseni videa
for a:=0 to high(bmp) do
begin
bmp[a].Height:=VideoHeight;
pixels[a]:=bmp[a].ScanLine[bmp[a].height-1];
//musi upravit i lowbmp
lowbmp.Height:=trunc(bmp[0].Height/RectSize)+3;
lowpix:=lowbmp.ScanLine[lowbmp.height-1];
end;
end;
procedure TChangeRecognition.setVideoRect(ax, ay, aw, ah, destw, desth:
integer);
begin
VideoX:=ax;
VideoY:=ay;
VideoW:=aw;
VideoH:=ah;
VideoWidth:=destw;
VideoHeight:=desth;
end;
procedure TChangeRecognition.setVideoW(const Value: integer);
begin
fVideoW := min(screen.Width,Value);
end;
procedure TChangeRecognition.setVideoWidth(const Value: integer);
var a:integer;
begin
//nastavi sirku videa
fVideoWidth := min(screen.Width,max(Value,1));
//zmeni rozliseni videa
for a:=0 to high(bmp) do
begin
bmp[a].Width:=VideoWidth;
pixels[a]:=bmp[a].ScanLine[bmp[a].height-1];
//musi upravit i lowbmp
lowbmp.Width:=trunc(bmp[0].Width/RectSize)+3;
lowpix:=lowbmp.ScanLine[lowbmp.height-1];
end;
end;
procedure TChangeRecognition.setVideoX(const Value: integer);
begin
fVideoX := max(Value,0);
end;
procedure TChangeRecognition.setVideoY(const Value: integer);
begin
fVideoY := max(Value,0);
end;
end.
Interalab napsal(a):
> Is the screengrabber application proprietary?
>
> [EMAIL PROTECTED] wrote:
>
>> Hi.
>>
>> Im so sorry i forgot change "licence" paragraph text. But as you can see
>> on my web pages http://www.cze.cz/?lang=en, the licence is GNU GPL.
>>
>> dabi du napsal(a):
>>
>>
>>> Hi, very interesting work.
>>>
>>> Could you please explain about terms of use, you say
>>> freeware open source but on your web site it says only
>>> for noncommercial us. How is it going to be in the
>>> future in terms of licesing.
>>>
>>> --- John Grden <[EMAIL PROTECTED]> wrote:
>>>
>>>
>>>
>>>
>>>> wow, very impressive video - The screen capture, i"m
>>>> sure, is going to get
>>>> alot of people trying it out for sure. That was
>>>> very cool to see.
>>>>
>>>> Nice work!
>>>>
>>>> On 4/15/07, [EMAIL PROTECTED] <[EMAIL PROTECTED]> wrote:
>>>>
>>>>
>>>>
>>>>> **Breeze is freeware open source web application
>>>>>
>>>>>
>>>>>
>>>> for chating, providing
>>>>
>>>>
>>>>
>>>>> and recording web seminars.
>>>>>
>>>>> Download (Windows & Linux all in one)
>>>>> Download from
>>>>>
>>>>>
>>>>>
>>>> http://rapidshare.com/files/25850249/Breeze.exe
>>>> (28118 KB)
>>>>
>>>>
>>>>
>>>>> or http://mirror1.cze.cz/download/breeze.exe
>>>>>
>>>>>
>>>>>
>>>> (28118 KB).
>>>>
>>>>
>>>>
>>>>> Online video tutorial
>>>>>
>>>>>
>>>>>
>>>> http://grafitchat.wz.cz/help.htm,
>>>>
>>>>
>>>>
>>>>> http://mirror1.cze.cz/download/breezehelp.htm.
>>>>>
>>>>>
>>>>> _______________________________________________
>>>>> Red5 mailing list
>>>>> [email protected]
>>>>>
>>>>>
>>>>>
>>>>>
>>>> http://osflash.org/mailman/listinfo/red5_osflash.org
>>>>
>>>>
>>>> --
>>>> [ JPG ]
>>>>
>>>>
>>>>
>>>>> _______________________________________________
>>>>>
>>>>>
>>>>>
>>>> Red5 mailing list
>>>> [email protected]
>>>> http://osflash.org/mailman/listinfo/red5_osflash.org
>>>>
>>>>
>>>>
>>>>
>>> __________________________________________________
>>> Do You Yahoo!?
>>> Tired of spam? Yahoo! Mail has the best spam protection around
>>> http://mail.yahoo.com
>>>
>>> _______________________________________________
>>> Red5 mailing list
>>> [email protected]
>>> http://osflash.org/mailman/listinfo/red5_osflash.org
>>>
>>>
>>>
>>>
>>>
>>>
>> _______________________________________________
>> Red5 mailing list
>> [email protected]
>> http://osflash.org/mailman/listinfo/red5_osflash.org
>>
>>
>
> _______________________________________________
> Red5 mailing list
> [email protected]
> http://osflash.org/mailman/listinfo/red5_osflash.org
>
>
>
> __________ Informace od NOD32 2195 (20070416) __________
>
> Tato zprava byla proverena antivirovym systemem NOD32.
> http://www.nod32.cz
>
>
>
>
_______________________________________________
Red5 mailing list
[email protected]
http://osflash.org/mailman/listinfo/red5_osflash.org