junkew Posted August 31, 2008 Share Posted August 31, 2008 Why does code below break?The difference is in first saving the screen to a file.BMP works correctlyWhen getting the BMP directly with lockbits things seem to be breaking when abs($Stride) * $Height) > 816It looks like I am getting some kind of an overflow and autoit fully breaks down with an exceptionBreaks on $pixelData = DllStructCreate("byte[" & (abs($Stride) * $Height) & "]", $Scan0) consolewrite("4 so far so good" & @CRLF) $BMPDataStart = DllStructGetData($pixeldata,1) consolewrite("5 so far NOT so good")Full code to demonstrateexpandcollapse popup#include <GDIPlus.au3> #Include <ScreenCapture.au3> Global Const $Bitmap1Filename = @TempDir & "\FULLSCREEN.bmp" ; Initialize GDI+ library _GDIPlus_Startup () ;Save the whole screen _ScreenCapture_Capture($Bitmap1Filename,0,0,-1,-1,false) testit() func testIt() Dim $BMP1Data="", $BMP1Width=0, $BMP1Height=0, $BMP1LineWidth=0; ; Load the bitmap to search in getImage($Bitmap1Filename, $BMP1Data, $BMP1Width, $BMP1Height, $BMP1LineWidth) ; Load the bitmap to search in getImage("SCREEN", $BMP1Data, $BMP1Width, $BMP1Height, $BMP1LineWidth) EndFunc Func GetImage($BMPFile, byref $BMPDataStart, byref $Width, byRef $Height, byref $Stride) ; Load the bitmap to search in If $BMPFile="SCREEN" Then $hbScreen=_ScreenCapture_Capture("") $pBitmap = _GDIPlus_BitmapCreateFromHBITMAP($hbScreen) Else $pBitmap = _GDIPlus_BitmapCreateFromFile($BMPFile) EndIf consolewrite("so far so good") ;Get $tagGDIPBITMAPDATA structure $BitmapData= _GDIPlus_BitmapLockBits($pBitmap, 0, 0, _GDIPlus_ImageGetWidth($pBitmap), _GDIPlus_ImageGetHeight($pBitmap), $GDIP_ILMREAD, $GDIP_PXF32RGB) If @ERROR Then MsgBox(0,"","Error locking region") consolewrite("2 so far so good" & @CRLF) $Stride = DllStructGetData($BitmapData, "Stride");Stride - Offset, in bytes, between consecutive scan lines of the bitmap. If the stride is positive, the bitmap is top-down. If the stride is negative, the bitmap is bottom-up. $Width = DllStructGetData($BitmapData, "Width");Image width - Number of pixels in one scan line of the bitmap. $Height = DllStructGetData($BitmapData, "Height");Image height - Number of scan lines in the bitmap. $PixelFormat = DllStructGetData($BitmapData, "PixelFormat") ;Pixel format - Integer that specifies the pixel format of the bitmap $Scan0 = DllStructGetData($BitmapData, "Scan0");Scan0 - Pointer to the first (index 0) scan line of the bitmap. ConsoleWrite("Bitmap Stride: " & $Stride & @CRLF) ConsoleWrite("Bitmap Width: " & $Width & @CRLF) ConsoleWrite("Bitmap Height: " & $Height & @CRLF) ConsoleWrite("Bitmap PixelFormat: " & $PixelFormat & @CRLF) ConsoleWrite("Bitmap Scan0: " & $Scan0 & @CRLF) consolewrite("3 so far so good" & @CRLF) $pixelData = DllStructCreate("byte[" & (abs($Stride) * $Height) & "]", $Scan0) consolewrite("4 so far so good" & @CRLF) $BMPDataStart = DllStructGetData($pixeldata,1) consolewrite("5 so far NOT so good") _GDIPlus_BitmapUnlockBits($pBitmap, $BitmapData) _GDIPlus_ImageDispose ($pBitmap) _WinAPI_DeleteObject ($pBitmap) EndFunc ;==>GetImage FAQ 31 How to click some elements, FAQ 40 Test automation with AutoIt, Multithreading CLR .NET Powershell CMDLets Link to comment Share on other sites More sharing options...
rover Posted September 1, 2008 Share Posted September 1, 2008 Why does code below break? The difference is in first saving the screen to a file.BMP works correctly When getting the BMP directly with lockbits things seem to be breaking when abs($Stride) * $Height) > 816 It looks like I am getting some kind of an overflow and autoit fully breaks down with an exception Breaks on $pixelData = DllStructCreate("byte[" & (abs($Stride) * $Height) & "]", $Scan0) consolewrite("4 so far so good" & @CRLF) $BMPDataStart = DllStructGetData($pixeldata,1) consolewrite("5 so far NOT so good") Full code to demonstrate expandcollapse popup#include <GDIPlus.au3> #Include <ScreenCapture.au3> Global Const $Bitmap1Filename = @TempDir & "\FULLSCREEN.bmp" ; Initialize GDI+ library _GDIPlus_Startup () ;Save the whole screen _ScreenCapture_Capture($Bitmap1Filename,0,0,-1,-1,false) testit() func testIt() Dim $BMP1Data="", $BMP1Width=0, $BMP1Height=0, $BMP1LineWidth=0; ; Load the bitmap to search in getImage($Bitmap1Filename, $BMP1Data, $BMP1Width, $BMP1Height, $BMP1LineWidth) ; Load the bitmap to search in getImage("SCREEN", $BMP1Data, $BMP1Width, $BMP1Height, $BMP1LineWidth) EndFunc Func GetImage($BMPFile, byref $BMPDataStart, byref $Width, byRef $Height, byref $Stride) ; Load the bitmap to search in If $BMPFile="SCREEN" Then $hbScreen=_ScreenCapture_Capture("") $pBitmap = _GDIPlus_BitmapCreateFromHBITMAP($hbScreen) Else $pBitmap = _GDIPlus_BitmapCreateFromFile($BMPFile) EndIf consolewrite("so far so good") ;Get $tagGDIPBITMAPDATA structure $BitmapData= _GDIPlus_BitmapLockBits($pBitmap, 0, 0, _GDIPlus_ImageGetWidth($pBitmap), _GDIPlus_ImageGetHeight($pBitmap), $GDIP_ILMREAD, $GDIP_PXF32RGB) If @ERROR Then MsgBox(0,"","Error locking region") consolewrite("2 so far so good" & @CRLF) $Stride = DllStructGetData($BitmapData, "Stride");Stride - Offset, in bytes, between consecutive scan lines of the bitmap. If the stride is positive, the bitmap is top-down. If the stride is negative, the bitmap is bottom-up. $Width = DllStructGetData($BitmapData, "Width");Image width - Number of pixels in one scan line of the bitmap. $Height = DllStructGetData($BitmapData, "Height");Image height - Number of scan lines in the bitmap. $PixelFormat = DllStructGetData($BitmapData, "PixelFormat") ;Pixel format - Integer that specifies the pixel format of the bitmap $Scan0 = DllStructGetData($BitmapData, "Scan0");Scan0 - Pointer to the first (index 0) scan line of the bitmap. ConsoleWrite("Bitmap Stride: " & $Stride & @CRLF) ConsoleWrite("Bitmap Width: " & $Width & @CRLF) ConsoleWrite("Bitmap Height: " & $Height & @CRLF) ConsoleWrite("Bitmap PixelFormat: " & $PixelFormat & @CRLF) ConsoleWrite("Bitmap Scan0: " & $Scan0 & @CRLF) consolewrite("3 so far so good" & @CRLF) $pixelData = DllStructCreate("byte[" & (abs($Stride) * $Height) & "]", $Scan0) consolewrite("4 so far so good" & @CRLF) $BMPDataStart = DllStructGetData($pixeldata,1) consolewrite("5 so far NOT so good") _GDIPlus_BitmapUnlockBits($pBitmap, $BitmapData) _GDIPlus_ImageDispose ($pBitmap) _WinAPI_DeleteObject ($pBitmap) EndFunc ;==>GetImage@junkew see this thread: http://www.autoitscript.com/forum/index.php?showtopic=76530 it helps to search for 'BitmapLockBits' Try this reworking of your example expandcollapse popup#include <GDIPlus.au3> #Include <ScreenCapture.au3> #include <GUIConstantsEX.au3> #include <Constants.au3> #include <WindowsConstants.au3> Global $pBitmap, $hGraphics Global Const $Bitmap1Filename = @TempDir & "\FULLSCREEN.bmp" $hwnd = GUICreate("_GDIPlus_BitmapLockBits() Test", 800, 600,-1,-1,-1,$WS_EX_TOPMOST) GUISetState() ; Initialize GDI+ library _GDIPlus_Startup () ;Save the whole screen _ScreenCapture_Capture($Bitmap1Filename,0,0,-1,-1,false) testit() While 1 $msg = GUIGetMsg() If $msg = $GUI_EVENT_CLOSE Then ExitLoop WEnd _GDIPlus_GraphicsDispose($hGraphics) _WinAPI_DeleteObject ($pBitmap) Exit func testIt() Dim $BMP1Data="", $BMP1Width=0, $BMP1Height=0, $BMP1LineWidth=0; ; Load the bitmap to search in getImage($Bitmap1Filename, $BMP1Data, $BMP1Width, $BMP1Height, $BMP1LineWidth) ; Load the bitmap to search in getImage("SCREEN", $BMP1Data, $BMP1Width, $BMP1Height, $BMP1LineWidth) EndFunc Func GetImage($BMPFile, byref $BMPDataStart, byref $Width, byRef $Height, byref $Stride) ; Load the bitmap to search in Local $hbScreen If $BMPFile="SCREEN" Then $hbScreen=_ScreenCapture_Capture("") $pBitmap = _GDIPlus_BitmapCreateFromHBITMAP($hbScreen) ConsoleWrite("SCREEN" & @CRLF) Else $pBitmap = _GDIPlus_BitmapCreateFromFile($BMPFile) ConsoleWrite("FILE" & @CRLF) EndIf ; Show pixel format for screen capture or file $aRet = _GDIPlus_ImageGetPixelFormat($pBitmap) ConsoleWrite("Image pixel format: " & $aRet[1] & @CRLF); ConsoleWrite("Image pixel format constant: " & $aRet[0] & @CRLF & @CRLF); ProgressOn("Image Search", "The image is being processed.", "0 percent", -1, -1, 16) ;Get $tagGDIPBITMAPDATA structure $BitmapData= _GDIPlus_BitmapLockBits($pBitmap, 0, 0, _GDIPlus_ImageGetWidth($pBitmap), _ _GDIPlus_ImageGetHeight($pBitmap), $GDIP_ILMREAD, $GDIP_PXF32RGB) If @ERROR Then MsgBox(0,"","Error locking region") $Stride = DllStructGetData($BitmapData, "Stride");Stride - Offset, in bytes, between consecutive scan lines of the bitmap. ;If the stride is positive, the bitmap is top-down. If the stride is negative, the bitmap is bottom-up. $Width = DllStructGetData($BitmapData, "Width");Image width - Number of pixels in one scan line of the bitmap. $Height = DllStructGetData($BitmapData, "Height");Image height - Number of scan lines in the bitmap. ;dataname is Format, not Pixelformat $PixelFormat = DllStructGetData($BitmapData, "Format") ;Pixel format - Integer that specifies the pixel format of the bitmap $Scan0 = DllStructGetData($BitmapData, "Scan0");Scan0 - Pointer to the first (index 0) scan line of the bitmap. ;$Scan0 not pointer to byte array For $row = 0 To $Height - 1 For $col = 0 To $Width - 1 $pixel = DllStructCreate("dword", $Scan0 + $row * $Stride + $col*4) ;ConsoleWrite(Hex(DllStructGetData($pixel, 1)) & @CRLF) Next ProgressSet(Int(100 * $row / ($Height)), Int(100 * $row / ($Height)) & " Percent" & @CRLF & "Data: " & Hex(DllStructGetData($pixel, 1))) ;ConsoleWrite("-------" & @CRLF) Next ConsoleWrite("Bitmap Stride: " & $Stride & @CRLF) ConsoleWrite("Bitmap Width: " & $Width & @CRLF) ConsoleWrite("Bitmap Height: " & $Height & @CRLF) ConsoleWrite("Bitmap PixelFormat: " & $PixelFormat & @CRLF) ConsoleWrite("Bitmap Scan0: " & $Scan0 & @CRLF & @CRLF) _GDIPlus_BitmapUnlockBits($pBitmap, $BitmapData) $hgraphics = _GDIPlus_GraphicsCreateFromHWND($hwnd) _GDIPlus_GraphicsDrawImageRect($hgraphics, $pBitmap, 0, 0, $Width, $Height) ;_WinAPI_DeleteObject ($pBitmap) If $hbScreen Then _WinAPI_DeleteObject($hbScreen) ProgressOff() EndFunc ;==>GetImage Func _GDIPlus_ImageGetPixelFormat($hImage) ;Returns pixel format of an image ;http://www.autoitscript.com/forum/index.php?showtopic=77741&hl=gdi Local $aResult, $aFormat[2] = [0, ""], $iError = 0 If ($hImage = -1) Or (Not $hImage) Then Return SetError(4, 1, $aFormat) Local $aPixelFormat[14][2] = _ [["1 Bpp Indexed", $GDIP_PXF01INDEXED], _ ["4 Bpp Indexed", $GDIP_PXF04INDEXED], _ ["8 Bpp Indexed", $GDIP_PXF08INDEXED], _ ["16 Bpp Grayscale", $GDIP_PXF16GRAYSCALE], _ ["16 Bpp RGB 555", $GDIP_PXF16RGB555], _ ["16 Bpp RGB 565", $GDIP_PXF16RGB565], _ ["16 Bpp ARGB 1555", $GDIP_PXF16ARGB1555], _ ["24 Bpp RGB", $GDIP_PXF24RGB], _ ["32 Bpp RGB", $GDIP_PXF32RGB], _ ["32 Bpp ARGB", $GDIP_PXF32ARGB], _ ["32 Bpp PARGB", $GDIP_PXF32PARGB], _ ["48 Bpp RGB", $GDIP_PXF48RGB], _ ["64 Bpp ARGB", $GDIP_PXF64ARGB], _ ["64 Bpp PARGB", $GDIP_PXF64PARGB]] $aResult = DllCall($ghGDIPDll, "int", "GdipGetImagePixelFormat", "hwnd", $hImage, "int*", 0) $iError = @error If @error Or IsArray($aResult) = 0 Then Return SetError($iError, 2, $aFormat) For $i = 0 To 13 If $aPixelFormat[$i][1] = $aResult[2] Then $aFormat[0] = $aPixelFormat[$i][1] $aFormat[1] = $aPixelFormat[$i][0] Return SetError($aResult[0], 0, $aFormat) EndIf Next Return SetError($aResult[0], 3, $aFormat) EndFunc ;==>_GDIPlus_ImageGetPixelFormat I see fascists... Link to comment Share on other sites More sharing options...
junkew Posted September 1, 2008 Author Share Posted September 1, 2008 I actually have seen that thread and searched the forum before posting the problem. The code I made is 95% based on the thread but the only difference is that I want to get all bytes at once and not one by one with a DWORD iteration. Based on the description there is no reason why the code should not work. It actually works when I load from bitmap files and it only doesn't work when I don't write the screenshot to a file first. Any help? FAQ 31 How to click some elements, FAQ 40 Test automation with AutoIt, Multithreading CLR .NET Powershell CMDLets Link to comment Share on other sites More sharing options...
Malkey Posted September 1, 2008 Share Posted September 1, 2008 I actually have seen that thread and searched the forum before posting the problem. The code I made is 95% based on the thread but the only difference is that I want to get all bytes at once and not one by one with a DWORD iteration. Based on the description there is no reason why the code should not work. It actually works when I load from bitmap files and it only doesn't work when I don't write the screenshot to a file first. Any help?This is as far as I got. I've given up for the night. I don't think it is 100% right. It may help you along, maybe. expandcollapse popup#include <GDIPlus.au3> #Include <ScreenCapture.au3> Global Const $Bitmap1Filename = @TempDir & "\FULLSCREEN.bmp" ; Initialize GDI+ library _GDIPlus_Startup () ;Save the whole screen _ScreenCapture_Capture($Bitmap1Filename,0,0,@DesktopWidth/4,@DesktopHeight/4,false) testit() func testIt() Dim $BMP1Data="", $BMP1Width=0, $BMP1Height=0, $BMP1LineWidth=0; ; Load the bitmap to search in getImage($Bitmap1Filename, $BMP1Data, $BMP1Width, $BMP1Height, $BMP1LineWidth) ; Load the bitmap to search in getImage("SCREEN", $BMP1Data, $BMP1Width, $BMP1Height, $BMP1LineWidth) EndFunc Func GetImage($BMPFile, byref $BMPDataStart, byref $Width, byRef $Height, byref $Stride) ; Load the bitmap to search in If $BMPFile="SCREEN" Then $hbScreen=_ScreenCapture_Capture("",0,0,@DesktopWidth/4,@DesktopHeight/4) $pBitmap = _GDIPlus_BitmapCreateFromHBITMAP($hbScreen) Else $pBitmap = _GDIPlus_BitmapCreateFromFile($BMPFile) EndIf consolewrite("so far so good") ;Get $tagGDIPBITMAPDATA structure $BitmapData= _GDIPlus_BitmapLockBits($pBitmap, 0, 0, _GDIPlus_ImageGetWidth($pBitmap), _GDIPlus_ImageGetHeight($pBitmap), $GDIP_ILMREAD, $GDIP_PXF32RGB) If @ERROR Then MsgBox(0,"","Error locking region") consolewrite("2 so far so good" & @CRLF) $Stride = DllStructGetData($BitmapData, "Stride");Stride - Offset, in bytes, between consecutive scan lines of the bitmap. If the stride is positive, the bitmap is top-down. If the stride is negative, the bitmap is bottom-up. $Width = DllStructGetData($BitmapData, "Width");Image width - Number of pixels in one scan line of the bitmap. $Height = DllStructGetData($BitmapData, "Height");Image height - Number of scan lines in the bitmap. $PixelFormat = DllStructGetData($BitmapData, "PixelFormat") ;Pixel format - Integer that specifies the pixel format of the bitmap $Scan0 = DllStructGetData($BitmapData, "Scan0");Scan0 - Pointer to the first (index 0) scan line of the bitmap. ConsoleWrite("Bitmap Stride: " & $Stride & @CRLF) ConsoleWrite("Bitmap Width: " & $Width & @CRLF) ConsoleWrite("Bitmap Height: " & $Height & @CRLF) ConsoleWrite("Bitmap PixelFormat: " & $PixelFormat & @CRLF) ConsoleWrite("Bitmap Scan0: " & $Scan0 & @CRLF) consolewrite("3 so far so good" & @CRLF) $pixelData = DllStructCreate("byte array[" & abs($Stride) * $Height*$Width*4 & "]", $Scan0) consolewrite("4 so far so good" & @CRLF) ;$BMPDataStart = DllStructGetData($pixeldata,1) for $x = 64 to 1 step -1 consolewrite(Hex(DllStructGetData($pixelData, 1, $x),2) ) if Mod($x,4) =0 then consolewrite(@CRLF) next consolewrite("5 so far NOT so good") _GDIPlus_BitmapUnlockBits($pBitmap, $BitmapData) _GDIPlus_ImageDispose ($pBitmap) _WinAPI_DeleteObject ($pBitmap) EndFunc ;==>GetImage The color format maybe 0xRRGGBBAA. I was expecting 0xAARRGGBB format. I don't Know. Link to comment Share on other sites More sharing options...
junkew Posted September 1, 2008 Author Share Posted September 1, 2008 Somehow it seems to be breaking on the DllStructGetData and seems not able to get the bytes.Is there any limitation in referencing to byte in a struct or am I using DllStructCreate in an incorrect manner$pixel = DllStructCreate("byte data[5242880]", $Scan0) ; Doesn't help (1280 * 1024 = 5242880consolewrite("Struct size " & (abs($Stride) * $Height) & ":" & DllStructGetSize ( $pixel) & @crlf)Struct size is correctly allocatedconsolewrite("NOT broken")It just breaks on this line only when (abs($Stride) * $Height) > nnn and only when getting bits from screen directly instead from file $BMPDataStart = DllStructGetData($pixel,"data")consolewrite("Broken code not reached")Just found out that the 816 is not static yesterday it was 817 when it breakstoday it works till value of 9184. Could it be that there is a special value on my screen that turns things into breaking????!!!!Just a weird problem I cannot explain and find a solution for sofar. FAQ 31 How to click some elements, FAQ 40 Test automation with AutoIt, Multithreading CLR .NET Powershell CMDLets Link to comment Share on other sites More sharing options...
rover Posted September 2, 2008 Share Posted September 2, 2008 I actually have seen that thread and searched the forum before posting the problem. The code I made is 95% based on the thread but the only difference is that I want to get all bytes at once and not one by one with a DWORD iteration. Based on the description there is no reason why the code should not work. It actually works when I load from bitmap files and it only doesn't work when I don't write the screenshot to a file first. Any help?my apologies junkew, sometimes I don't see the trees for the forest... I thought $Scan0 was pointer to array of pointers?, unclear on this area myself. or max size of byte array of struct was exceeded. anyway the screencapture is a 32bit (8 alpha bits unused) memory bitmap, cloning the image with a 24 bitmap header works expandcollapse popup#include <GDIPlus.au3> #include <ScreenCapture.au3> ; GDI+ Image File Format Constants ; Globally Unique Identifier (GUID) Global Const $GDIP_IMAGEFORMAT_UNDEFINED = "{B96B3CA9-0728-11D3-9D7B-0000F81EF32E}" ; Windows GDI+ is unable to determine the format. Global Const $GDIP_IMAGEFORMAT_MEMORYBMP = "{B96B3CAA-0728-11D3-9D7B-0000F81EF32E}" ; Image was constructed from a memory bitmap. Global Const $GDIP_IMAGEFORMAT_BMP = "{B96B3CAB-0728-11D3-9D7B-0000F81EF32E}" ; Microsoft Windowsbitmap (BMP) format. Global Const $GDIP_IMAGEFORMAT_EMF = "{B96B3CAC-0728-11D3-9D7B-0000F81EF32E}" ; Enhanced Metafile (EMF) format. Global Const $GDIP_IMAGEFORMAT_WMF = "{B96B3CAD-0728-11D3-9D7B-0000F81EF32E}" ; Windows Metafile Format (WMF) format. Global Const $GDIP_IMAGEFORMAT_JPEG = "{B96B3CAE-0728-11D3-9D7B-0000F81EF32E}" ; JPEG format. Global Const $GDIP_IMAGEFORMAT_PNG = "{B96B3CAF-0728-11D3-9D7B-0000F81EF32E}" ; Portable Network Graphics (PNG) format. Global Const $GDIP_IMAGEFORMAT_GIF = "{B96B3CB0-0728-11D3-9D7B-0000F81EF32E}" ; Graphics Interchange Format (GIF) format. Global Const $GDIP_IMAGEFORMAT_TIFF = "{B96B3CB1-0728-11D3-9D7B-0000F81EF32E}" ; Tagged Image File Format (TIFF) format. Global Const $GDIP_IMAGEFORMAT_EXIF = "{B96B3CB2-0728-11D3-9D7B-0000F81EF32E}" ; Exif (Exchangeable Image File) format. Global Const $GDIP_IMAGEFORMAT_ICON = "{B96B3CB5-0728-11D3-9D7B-0000F81EF32E}" ; Icon format. Global Const $Bitmap1Filename = @TempDir & "\FULLSCREEN.bmp" ; Initialize GDI+ library _GDIPlus_Startup() ;Save the whole screen _ScreenCapture_Capture($Bitmap1Filename, 0, 0, -1, -1, False) testIt() Func testIt() Dim $BMP1Data = "", $BMP1Width = 0, $BMP1Height = 0, $BMP1LineWidth = 0; ; Load the bitmap to search in GetImage($Bitmap1Filename, $BMP1Data, $BMP1Width, $BMP1Height, $BMP1LineWidth) ; Load the bitmap to search in GetImage("SCREEN", $BMP1Data, $BMP1Width, $BMP1Height, $BMP1LineWidth) EndFunc ;==>testIt Func GetImage($BMPFile, ByRef $BMPDataStart, ByRef $Width, ByRef $Height, ByRef $Stride) ; Load the bitmap to search in If $BMPFile = "SCREEN" Then $hbScreen = _ScreenCapture_Capture("") $pBitmapCap = _GDIPlus_BitmapCreateFromHBITMAP($hbScreen) ; returns memory bitmap ConsoleWrite(@CRLF & '-_GDIPlus_ImageGetRawFormat($pBitmap) = ' & _GDIPlus_ImageGetRawFormat($pBitmapCap) & @CRLF) ; Show pixel format for screen capture $aRet = _GDIPlus_ImageGetPixelFormat($pBitmapCap) ConsoleWrite("$pBitmapCap pixel format: " & $aRet[1] & @CRLF) $pBitmap = _GDIPlus_BitmapCloneArea($pBitmapCap, 0, 0, _GDIPlus_ImageGetWidth($pBitmapCap), _ _GDIPlus_ImageGetHeight($pBitmapCap), $GDIP_PXF24RGB) _WinAPI_DeleteObject($pBitmapCap) ; Show pixel format for screen capture or file $aRet = _GDIPlus_ImageGetPixelFormat($pBitmap) ConsoleWrite("$hClone pixel format: " & $aRet[1] & @CRLF) Else $pBitmap = _GDIPlus_BitmapCreateFromFile($BMPFile) ConsoleWrite('-_GDIPlus_ImageGetRawFormat($pBitmap) = ' & _GDIPlus_ImageGetRawFormat($pBitmap) & @CRLF) ; Show pixel format for screen capture or file $aRet = _GDIPlus_ImageGetPixelFormat($pBitmap) ConsoleWrite("Image pixel format: " & $aRet[1] & @CRLF); EndIf ;Get $tagGDIPBITMAPDATA structure $BitmapData = _GDIPlus_BitmapLockBits($pBitmap, 0, 0, _GDIPlus_ImageGetWidth($pBitmap), _ _GDIPlus_ImageGetHeight($pBitmap), $GDIP_ILMREAD, $GDIP_PXF24RGB) If @error Then MsgBox(0, "", "Error locking region") $Stride = DllStructGetData($BitmapData, "Stride");Stride - Offset, in bytes, between consecutive scan lines of the bitmap. If the stride is positive, the bitmap is top-down. If the stride is negative, the bitmap is bottom-up. $Width = DllStructGetData($BitmapData, "Width");Image width - Number of pixels in one scan line of the bitmap. $Height = DllStructGetData($BitmapData, "Height");Image height - Number of scan lines in the bitmap. $PixelFormat = DllStructGetData($BitmapData, "Format") ;Pixel format - Integer that specifies the pixel format of the bitmap $Scan0 = DllStructGetData($BitmapData, "Scan0");Scan0 - Pointer to the first (index 0) scan line of the bitmap. ConsoleWrite("Bitmap Stride: " & $Stride & @CRLF) ConsoleWrite("Bitmap Width: " & $Width & @CRLF) ConsoleWrite("Bitmap Height: " & $Height & @CRLF) ConsoleWrite("Bitmap PixelFormat: " & $PixelFormat & @CRLF) ConsoleWrite("Bitmap Scan0: " & $Scan0 & @CRLF) $pixelData = DllStructCreate("byte[" & (Abs($Stride) * $Height) & "]", $Scan0) $BMPDataStart = DllStructGetData($pixelData, 1) ConsoleWrite('+BinaryLen($BMPDataStart) = ' & BinaryLen($BMPDataStart) & @CRLF & @CRLF) _GDIPlus_BitmapUnlockBits($pBitmap, $BitmapData) _GDIPlus_ImageDispose($pBitmap) _WinAPI_DeleteObject($pBitmap) EndFunc ;==>GetImage Func _GDIPlus_ImageGetRawFormat($hImage) ;Returns file format GUID string and image type identifier string Local $aResult1, $aResult2, $tStruc, $iError = 0 If ($hImage = -1) Or (Not $hImage) Then Return SetError(4, 1, "") Local $aImageType[11][2] = _ [["UNDEFINED", $GDIP_IMAGEFORMAT_UNDEFINED], _ ["MEMORYBMP", $GDIP_IMAGEFORMAT_MEMORYBMP], _ ["BMP", $GDIP_IMAGEFORMAT_BMP], _ ["EMF", $GDIP_IMAGEFORMAT_EMF], _ ["WMF", $GDIP_IMAGEFORMAT_WMF], _ ["JPEG", $GDIP_IMAGEFORMAT_JPEG], _ ["PNG", $GDIP_IMAGEFORMAT_PNG], _ ["GIF", $GDIP_IMAGEFORMAT_GIF], _ ["TIFF", $GDIP_IMAGEFORMAT_TIFF], _ ["EXIF", $GDIP_IMAGEFORMAT_EXIF], _ ["ICON", $GDIP_IMAGEFORMAT_ICON]] $tStruc = DllStructCreate("byte[16]") $iError = @error If @error Or (Not IsDllStruct($tStruc)) Then Return SetError($iError, 2, "") $aResult1 = DllCall($ghGDIPDll, "int", "GdipGetImageRawFormat", "hwnd", $hImage, _ "ptr", DllStructGetPtr($tStruc)) $iError = @error If @error Or (Not IsArray($aResult1)) Or (Not IsPtr($aResult1[2])) Or _ (Not $aResult1[2]) Then Return SetError($iError, 3, "") $aResult2 = DllCall("Ole32.dll", "int", "StringFromGUID2", "ptr", $aResult1[2], "wstr", "", "int", 40) $iError = @error If @error Or (Not IsArray($aResult2)) Or (Not $aResult2[2]) Then Return SetError($iError, 4, "") For $i = 0 To 10 If $aImageType[$i][1] == $aResult2[2] Then Return SetError($aResult1[0], 0, $aImageType[$i][0]) EndIf Next Return SetError($aResult2[0], 5, "") EndFunc ;==>_GDIPlus_ImageGetRawFormat Func _GDIPlus_ImageGetPixelFormat($hImage) ;Returns pixel format of an image ;http://www.autoitscript.com/forum/index.php?showtopic=77741&hl=gdi Local $aResult, $aFormat[2] = [0, ""], $iError = 0 If ($hImage = -1) Or (Not $hImage) Then Return SetError(4, 1, $aFormat) Local $aPixelFormat[14][2] = _ [["1 Bpp Indexed", $GDIP_PXF01INDEXED], _ ["4 Bpp Indexed", $GDIP_PXF04INDEXED], _ ["8 Bpp Indexed", $GDIP_PXF08INDEXED], _ ["16 Bpp Grayscale", $GDIP_PXF16GRAYSCALE], _ ["16 Bpp RGB 555", $GDIP_PXF16RGB555], _ ["16 Bpp RGB 565", $GDIP_PXF16RGB565], _ ["16 Bpp ARGB 1555", $GDIP_PXF16ARGB1555], _ ["24 Bpp RGB", $GDIP_PXF24RGB], _ ["32 Bpp RGB", $GDIP_PXF32RGB], _ ["32 Bpp ARGB", $GDIP_PXF32ARGB], _ ["32 Bpp PARGB", $GDIP_PXF32PARGB], _ ["48 Bpp RGB", $GDIP_PXF48RGB], _ ["64 Bpp ARGB", $GDIP_PXF64ARGB], _ ["64 Bpp PARGB", $GDIP_PXF64PARGB]] $aResult = DllCall($ghGDIPDll, "int", "GdipGetImagePixelFormat", "hwnd", $hImage, "int*", 0) $iError = @error If @error Or IsArray($aResult) = 0 Then Return SetError($iError, 2, $aFormat) For $i = 0 To 13 If $aPixelFormat[$i][1] = $aResult[2] Then $aFormat[0] = $aPixelFormat[$i][1] $aFormat[1] = $aPixelFormat[$i][0] Return SetError($aResult[0], 0, $aFormat) EndIf Next Return SetError($aResult[0], 3, $aFormat) EndFunc ;==>_GDIPlus_ImageGetPixelFormat I see fascists... Link to comment Share on other sites More sharing options...
Malkey Posted September 2, 2008 Share Posted September 2, 2008 my apologies junkew, sometimes I don't see the trees for the forest... I thought $Scan0 was pointer to array of pointers?, unclear on this area myself. or max size of byte array of struct was exceeded. anyway the screencapture is a 32bit (8 alpha bits unused) memory bitmap, cloning the image with a 24 bitmap header worksWell done rover. I had given up trying to solve this one. Also, the 32 bit bitmap with ARGB works. expandcollapse popup#include <GDIPlus.au3> #include <ScreenCapture.au3> ; GDI+ Image File Format Constants ; Globally Unique Identifier (GUID) Global Const $GDIP_IMAGEFORMAT_UNDEFINED = "{B96B3CA9-0728-11D3-9D7B-0000F81EF32E}" ; Windows GDI+ is unable to determine the format. Global Const $GDIP_IMAGEFORMAT_MEMORYBMP = "{B96B3CAA-0728-11D3-9D7B-0000F81EF32E}" ; Image was constructed from a memory bitmap. Global Const $GDIP_IMAGEFORMAT_BMP = "{B96B3CAB-0728-11D3-9D7B-0000F81EF32E}" ; Microsoft Windowsbitmap (BMP) format. Global Const $GDIP_IMAGEFORMAT_EMF = "{B96B3CAC-0728-11D3-9D7B-0000F81EF32E}" ; Enhanced Metafile (EMF) format. Global Const $GDIP_IMAGEFORMAT_WMF = "{B96B3CAD-0728-11D3-9D7B-0000F81EF32E}" ; Windows Metafile Format (WMF) format. Global Const $GDIP_IMAGEFORMAT_JPEG = "{B96B3CAE-0728-11D3-9D7B-0000F81EF32E}" ; JPEG format. Global Const $GDIP_IMAGEFORMAT_PNG = "{B96B3CAF-0728-11D3-9D7B-0000F81EF32E}" ; Portable Network Graphics (PNG) format. Global Const $GDIP_IMAGEFORMAT_GIF = "{B96B3CB0-0728-11D3-9D7B-0000F81EF32E}" ; Graphics Interchange Format (GIF) format. Global Const $GDIP_IMAGEFORMAT_TIFF = "{B96B3CB1-0728-11D3-9D7B-0000F81EF32E}" ; Tagged Image File Format (TIFF) format. Global Const $GDIP_IMAGEFORMAT_EXIF = "{B96B3CB2-0728-11D3-9D7B-0000F81EF32E}" ; Exif (Exchangeable Image File) format. Global Const $GDIP_IMAGEFORMAT_ICON = "{B96B3CB5-0728-11D3-9D7B-0000F81EF32E}" ; Icon format. Global Const $Bitmap1Filename = @TempDir & "\FULLSCREEN.bmp" ; Initialize GDI+ library _GDIPlus_Startup() ;Save the whole screen _ScreenCapture_Capture($Bitmap1Filename, 0, 0, @DesktopWidth / 4, @DesktopHeight / 4, False) testIt() Func testIt() Dim $BMP1Data = "", $BMP1Width = 0, $BMP1Height = 0, $BMP1LineWidth = 0; ; Load the bitmap to search in GetImage($Bitmap1Filename, $BMP1Data, $BMP1Width, $BMP1Height, $BMP1LineWidth) ; Load the bitmap to search in GetImage("SCREEN", $BMP1Data, $BMP1Width, $BMP1Height, $BMP1LineWidth) EndFunc ;==>testIt Func GetImage($BMPFile, ByRef $BMPDataStart, ByRef $Width, ByRef $Height, ByRef $Stride) ; Load the bitmap to search in If $BMPFile = "SCREEN" Then $hbScreen = _ScreenCapture_Capture("", 0, 0, @DesktopWidth / 4, @DesktopHeight / 4, False) $pBitmapCap = _GDIPlus_BitmapCreateFromHBITMAP($hbScreen) ; returns memory bitmap ConsoleWrite(@CRLF & '-_GDIPlus_ImageGetRawFormat($pBitmap) = ' & _GDIPlus_ImageGetRawFormat($pBitmapCap) & @CRLF) ; Show pixel format for screen capture $aRet = _GDIPlus_ImageGetPixelFormat($pBitmapCap) ConsoleWrite("$pBitmapCap pixel format: " & $aRet[1] & @CRLF) $pBitmap = _GDIPlus_BitmapCloneArea($pBitmapCap, 0, 0, _GDIPlus_ImageGetWidth($pBitmapCap), _ _GDIPlus_ImageGetHeight($pBitmapCap), $GDIP_PXF32ARGB) ; $GDIP_PXF24RGB) _WinAPI_DeleteObject($pBitmapCap) ; Show pixel format for screen capture or file $aRet = _GDIPlus_ImageGetPixelFormat($pBitmap) ConsoleWrite("$hClone pixel format: " & $aRet[1] & @CRLF) Else $pBitmap = _GDIPlus_BitmapCreateFromFile($BMPFile) ConsoleWrite('-_GDIPlus_ImageGetRawFormat($pBitmap) = ' & _GDIPlus_ImageGetRawFormat($pBitmap) & @CRLF) ; Show pixel format for screen capture or file $aRet = _GDIPlus_ImageGetPixelFormat($pBitmap) ;ConsoleWrite("Image pixel format: " & $aRet[1] & @CRLF); EndIf ;Get $tagGDIPBITMAPDATA structure $BitmapData = _GDIPlus_BitmapLockBits($pBitmap, 0, 0, _GDIPlus_ImageGetWidth($pBitmap), _ _GDIPlus_ImageGetHeight($pBitmap), $GDIP_ILMREAD, $GDIP_PXF32ARGB) ; $GDIP_PXF24RGB) If @error Then MsgBox(0, "", "Error locking region") $Stride = DllStructGetData($BitmapData, "Stride");Stride - Offset, in bytes, between consecutive scan lines of the bitmap. If the stride is positive, the bitmap is top-down. If the stride is negative, the bitmap is bottom-up. $Width = DllStructGetData($BitmapData, "Width");Image width - Number of pixels in one scan line of the bitmap. $Height = DllStructGetData($BitmapData, "Height");Image height - Number of scan lines in the bitmap. $PixelFormat = DllStructGetData($BitmapData, "Format") ;Pixel format - Integer that specifies the pixel format of the bitmap $Scan0 = DllStructGetData($BitmapData, "Scan0");Scan0 - Pointer to the first (index 0) scan line of the bitmap. ConsoleWrite("Bitmap Stride: " & $Stride & @CRLF) ConsoleWrite("Bitmap Width: " & $Width & @CRLF) ConsoleWrite("Bitmap Height: " & $Height & @CRLF) ConsoleWrite("Bitmap PixelFormat: " & Hex($PixelFormat) & @CRLF) ConsoleWrite("Bitmap Scan0: " & $Scan0 & @CRLF) $pixelData = DllStructCreate("int[" & ($Width * $Height) & "]", $Scan0) $BMPDataStart = DllStructGetData($pixelData, 1) ConsoleWrite('+BinaryLen($BMPDataStart) = ' & BinaryLen($BMPDataStart) & @CRLF & @CRLF) For $x = 1 To $Width * $Height ConsoleWrite(Hex(DllStructGetData($pixelData, 1, $x)) & " ") If Mod($x, $Width) = 0 Then ConsoleWrite(@CRLF) Next _GDIPlus_BitmapUnlockBits($pBitmap, $BitmapData) _GDIPlus_ImageDispose($pBitmap) _WinAPI_DeleteObject($pBitmap) EndFunc ;==>GetImage Func _GDIPlus_ImageGetRawFormat($hImage) ;Returns file format GUID string and image type identifier string Local $aResult1, $aResult2, $tStruc, $iError = 0 If ($hImage = -1) Or (Not $hImage) Then Return SetError(4, 1, "") Local $aImageType[11][2] = _ [["UNDEFINED", $GDIP_IMAGEFORMAT_UNDEFINED], _ ["MEMORYBMP", $GDIP_IMAGEFORMAT_MEMORYBMP], _ ["BMP", $GDIP_IMAGEFORMAT_BMP], _ ["EMF", $GDIP_IMAGEFORMAT_EMF], _ ["WMF", $GDIP_IMAGEFORMAT_WMF], _ ["JPEG", $GDIP_IMAGEFORMAT_JPEG], _ ["PNG", $GDIP_IMAGEFORMAT_PNG], _ ["GIF", $GDIP_IMAGEFORMAT_GIF], _ ["TIFF", $GDIP_IMAGEFORMAT_TIFF], _ ["EXIF", $GDIP_IMAGEFORMAT_EXIF], _ ["ICON", $GDIP_IMAGEFORMAT_ICON]] $tStruc = DllStructCreate("byte[16]") $iError = @error If @error Or (Not IsDllStruct($tStruc)) Then Return SetError($iError, 2, "") $aResult1 = DllCall($ghGDIPDll, "int", "GdipGetImageRawFormat", "hwnd", $hImage, _ "ptr", DllStructGetPtr($tStruc)) $iError = @error If @error Or (Not IsArray($aResult1)) Or (Not IsPtr($aResult1[2])) Or _ (Not $aResult1[2]) Then Return SetError($iError, 3, "") $aResult2 = DllCall("Ole32.dll", "int", "StringFromGUID2", "ptr", $aResult1[2], "wstr", "", "int", 40) $iError = @error If @error Or (Not IsArray($aResult2)) Or (Not $aResult2[2]) Then Return SetError($iError, 4, "") For $i = 0 To 10 If $aImageType[$i][1] == $aResult2[2] Then Return SetError($aResult1[0], 0, $aImageType[$i][0]) EndIf Next Return SetError($aResult2[0], 5, "") EndFunc ;==>_GDIPlus_ImageGetRawFormat Func _GDIPlus_ImageGetPixelFormat($hImage) ;Returns pixel format of an image ;http://www.autoitscript.com/forum/index.php?showtopic=77741&hl=gdi Local $aResult, $aFormat[2] = [0, ""], $iError = 0 If ($hImage = -1) Or (Not $hImage) Then Return SetError(4, 1, $aFormat) Local $aPixelFormat[14][2] = _ [["1 Bpp Indexed", $GDIP_PXF01INDEXED], _ ["4 Bpp Indexed", $GDIP_PXF04INDEXED], _ ["8 Bpp Indexed", $GDIP_PXF08INDEXED], _ ["16 Bpp Grayscale", $GDIP_PXF16GRAYSCALE], _ ["16 Bpp RGB 555", $GDIP_PXF16RGB555], _ ["16 Bpp RGB 565", $GDIP_PXF16RGB565], _ ["16 Bpp ARGB 1555", $GDIP_PXF16ARGB1555], _ ["24 Bpp RGB", $GDIP_PXF24RGB], _ ["32 Bpp RGB", $GDIP_PXF32RGB], _ ["32 Bpp ARGB", $GDIP_PXF32ARGB], _ ["32 Bpp PARGB", $GDIP_PXF32PARGB], _ ["48 Bpp RGB", $GDIP_PXF48RGB], _ ["64 Bpp ARGB", $GDIP_PXF64ARGB], _ ["64 Bpp PARGB", $GDIP_PXF64PARGB]] $aResult = DllCall($ghGDIPDll, "int", "GdipGetImagePixelFormat", "hwnd", $hImage, "int*", 0) $iError = @error If @error Or IsArray($aResult) = 0 Then Return SetError($iError, 2, $aFormat) For $i = 0 To 13 If $aPixelFormat[$i][1] = $aResult[2] Then $aFormat[0] = $aPixelFormat[$i][1] $aFormat[1] = $aPixelFormat[$i][0] Return SetError($aResult[0], 0, $aFormat) EndIf Next Return SetError($aResult[0], 3, $aFormat) EndFunc ;==>_GDIPlus_ImageGetPixelFormat Link to comment Share on other sites More sharing options...
junkew Posted September 2, 2008 Author Share Posted September 2, 2008 thx rover for the well documented solution. I can work with the 24bits solution (although it leaves me clueless why it breaks with the PXF32RGB) GDIPlus_BitmapCloneArea seems not needed as lockbits function takes care of it. Unfortunately there is not much speed gain by getting the desktop directly instead of writing/reading to file (saves 100-200 milliseconds on whole desktop which is not much gain as part of whole algoritm I am working on). FAQ 31 How to click some elements, FAQ 40 Test automation with AutoIt, Multithreading CLR .NET Powershell CMDLets Link to comment Share on other sites More sharing options...
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now