Monochromzeichnen eines Bildes

  • Hallöchen,
    Habe hier dieses Skript gebastelt, welches ein jpg zu einem Monochrom (Schwarz/Weiß)-Bild "umwandelt". Funktioniert auch super! Nur Frage ich mich, ob es nicht einen Weg gibt, die Geschwindigkeit des ganzen zu optimieren?

    Ich erinnere mich, dass Andy mal vor einigen Tagen erwähnte, er habe für das englische Forum eine PixelGetColor / PixelSearch Funktion geschrieben die sehr viel schneller arbeitet (Kann mich aber auch irren !)

    Auf das PixelGetColor kann ich leider nicht verzichten. Das Programm soll noch so erweitert werden, dass es das Bild zB. in Paint nachmalt (per Mousemove/Mouseclick). Deswegen brauche ich die einzelnen Pixelfarben in einem Array

    Spoiler anzeigen
    [autoit]

    $FilePath = FileOpenDialog("", "", "JPG (*.jpg)")
    If @error Then Exit

    [/autoit] [autoit][/autoit] [autoit]

    #include <GDIPlus.au3>
    #include <Array.au3>
    #include <Color.au3>
    #include <File.au3>
    _GDIPlus_Startup()

    [/autoit] [autoit][/autoit] [autoit]

    Global Const $AC_SRC_ALPHA = 1

    [/autoit] [autoit][/autoit] [autoit]

    $img_hwnd = _GDIPlus_ImageLoadFromFile($FilePath)
    $img_w = _GDIPlus_ImageGetWidth($img_hwnd)
    $img_h = _GDIPlus_ImageGetHeight($img_hwnd)
    _GDIPlus_ImageDispose($img_hwnd)

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    $guiMain = GUICreate("", $img_w, $img_h + 50, -1, -1)
    $ctrl_Einlesen = GUICtrlCreateButton("Einlesen", 0, $img_h, $img_w, 25)
    $ctrl_Progress = GUICtrlCreateProgress(0, $img_h + 25, $img_w, 25)
    $guiChild = GUICreate("", $img_w, $img_h, 0, 0, 0x40000000, Default, $guiMain)
    GUICtrlCreatePic($FilePath, 0, 0, 0, 0)
    $guiChild2 = GUICreate("", $img_w, $img_h, 0, 0, 0x40000000, Default, $guiMain)

    [/autoit] [autoit][/autoit] [autoit]

    GUISetState(@SW_SHOW, $guiMain)
    GUISetState(@SW_SHOW, $guiChild)

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    ;~ _ColorGetBlue()
    While 1
    $nMsg = GUIGetMsg()
    Switch $nMsg
    Case $ctrl_Einlesen
    _ImageDrawBlackAndWhite($guiChild, 115)
    Case -3
    Exit
    EndSwitch
    WEnd

    [/autoit] [autoit][/autoit] [autoit]

    Func _ImageDrawBlackAndWhite($hWnd, $iTol=115, $iArray=0)
    Local $xPos = 0, $yPos = 0, $aRet[$img_h*$img_w+1]
    $opt_Mode = Opt("PixelCoordMode", 2)
    ConsoleWrite("+> " & $img_h * $img_w & @CR & @CR)
    $hGraphic = _GDIPlus_GraphicsCreateFromHWND($hWnd)
    $hPenBlack = _GDIPlus_PenCreate(0xFF000000)
    $hPenWhite = _GDIPlus_PenCreate(0xFFFFFFFF)

    [/autoit] [autoit][/autoit] [autoit]

    For $i = 1 To ($img_h * $img_w)
    $iTmp = _ColorToBrightness(PixelGetColor($xPos, $yPos), 1, $iTol)
    If $iTmp = 0xFFFFFF Then _GDIPlus_GraphicsDrawLine ($hGraphic, $xPos, $yPos, $xPos-1, $yPos, $hPenWhite)
    If $iTmp = 0x000000 Then _GDIPlus_GraphicsDrawLine ($hGraphic, $xPos, $yPos, $xPos-1, $yPos, $hPenBlack)
    If $iArray = 1 Then $aRet[$i] = $iTmp

    [/autoit] [autoit][/autoit] [autoit]

    $xPos += 1
    If $xPos = $img_w Then
    GUICtrlSetData($ctrl_Progress, $i / ($img_h * $img_w) * 100)
    ConsoleWrite("+> " & $i & " / " & $img_h * $img_w & " ("&Round($i / ($img_h * $img_w) * 100,1)&" %) "&@CR & @CR)
    $xPos = 0
    $yPos += 1
    EndIf
    Next
    GUICtrlSetData($ctrl_Progress, 0)
    If $iArray=1 Then Return $aRet

    [/autoit] [autoit][/autoit] [autoit]

    EndFunc ;==>_ImageDrawBlackAndWhite

    [/autoit] [autoit][/autoit] [autoit]

    Func _ColorToBrightness($iColor, $iBlackAndWhite = 1, $iTol = 115)
    Local $aRet, $aTemp[3] = [_ColorGetRed($iColor), _ColorGetGreen($iColor), _ColorGetBlue($iColor)]
    $aRet = _ColorConvertRGBtoHSL($aTemp)
    If $iBlackAndWhite = 1 Then
    If $aRet[2] < $iTol Then
    Return 0x000000
    Else
    Return 0xFFFFFF
    EndIf
    EndIf
    Return $aRet[2]
    EndFunc ;==>_ColorToBrightness

    [/autoit]

    EDIT: hab mal ein Bild in den Anhang geladen, um zu zeigen was dabei rauskommt

    EDIT2: Habe grade das hier gefunden:

    Spoiler anzeigen
    [autoit]

    #include <GUIConstants.au3>
    #include <EditConstants.au3>
    #include <WindowsConstants.au3>
    #include <Color.au3>
    #include <WinAPI.au3>

    [/autoit] [autoit][/autoit] [autoit]

    Global $threshold
    Global $image
    Global $width
    Global $height
    Global $pixels
    Global $pathString = "12345678"
    Global $scramble = False
    Global $rotate = 0
    Global $speed

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    ;; Check hotkeys ;;
    If (Not HotKeySet ("{F9}", "Nothing")) Then
    MsgBox (16, "Error", "Could not register the F9 hotkey.")
    Exit
    EndIf
    If (Not HotKeySet ("{F10}", "Nothing")) Then
    MsgBox (16, "Erro", "Could not register the F10 hotkey.")
    Exit
    EndIf

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    ;; Image dialog ;;
    $imageFile = FileOpenDialog ("Open image", "", "Images (*.jpg;*.jpeg;*.gif;*.png;*.bmp)", 1)
    If (@error) Then Exit

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    ;; Options dialog ;;
    $optGUI = GUICreate ("Settings", 160, 270, -1, -1, $WS_CAPTION, BitOr ($WS_EX_APPWINDOW, $WS_EX_TOOLWINDOW))
    GUICtrlCreateGroup ("Image processing", 5, 5, 150, 85)
    GUICtrlCreateLabel ("Sensitivity (0~255):", 10, 28, 110, 15)
    $thresholdInput = GUICtrlCreateInput ("100", 125, 25, 25, 20, $ES_NUMBER)
    GUICtrlCreateLabel ("Width (px):", 10, 48, 110, 15)
    $widthInput = GUICtrlCreateInput ("100", 125, 45, 25, 20, $ES_NUMBER)
    GUICtrlCreateLabel ("Height (px):", 10, 68, 110, 15)
    $heightInput = GUICtrlCreateInput ("100", 125, 65, 25, 20, $ES_NUMBER)
    GUICtrlCreateGroup ("Drawing pattern", 5, 95, 150, 140)
    $horizontalRadio = GUICtrlCreateRadio ("Horizontal", 10, 115, 110, 15)
    $verticalRadio = GUICtrlCreateRadio ("Vertical", 10, 135, 110, 15)
    $diagonalRadio = GUICtrlCreateRadio ("Diagonal", 10, 155, 110, 15)
    $rotateRadio = GUICtrlCreateRadio ("Spiral", 10, 175, 110, 15)
    $scrambleRadio = GUICtrlCreateRadio ("Random", 10, 195, 110, 15)
    GUICtrlSetState ($diagonalRadio, $GUI_CHECKED)
    GUICtrlCreateLabel ("Mouse speed (0~100):", 10, 213, 110, 15)
    $speedInput = GUICtrlCreateInput ("0", 125, 210, 25, 20, $ES_NUMBER)
    $okBtn = GUICtrlCreateButton ("Ok", 30, 245, 40, 20)
    $cancelBtn = GUICtrlCreateButton ("Cancel", 80, 245, 50, 20)
    GUISetState ()

    [/autoit] [autoit][/autoit] [autoit]

    While 1
    Switch (GUIGetMsg ())
    Case $GUI_EVENT_CLOSE
    Exit
    Case $cancelBtn
    Exit
    Case $okBtn
    $threshold = GUICtrlRead ($thresholdInput)
    $width = GUICtrlRead ($widthInput)
    $height = GUICtrlRead ($heightInput)
    $speed = GUICtrlRead ($speedInput)
    If (GUICtrlRead ($horizontalRadio) == $GUI_CHECKED) Then
    $pathString = "45273618"
    ElseIf (GUICtrlRead ($verticalRadio) == $GUI_CHECKED) Then
    $pathString = "27453618"
    ElseIf (GUICtrlRead ($diagonalRadio) == $GUI_CHECKED) Then
    $pathString = "36184527"
    ElseIf (GUICtrlRead ($rotateRadio) == $GUI_CHECKED) Then
    $pathString = "14678532"
    $rotate = 1
    ElseIf (GUICtrlRead ($scrambleRadio) == $GUI_CHECKED) Then
    $scramble = True
    EndIf

    [/autoit] [autoit][/autoit] [autoit]

    GUIDelete ($optGUI)
    ExitLoop
    EndSwitch
    WEnd

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    ;; Processing dialog ;;
    $GUI = GUICreate ("Processing image...", $width, $height + 20, -1, -1, $WS_CAPTION, BitOr ($WS_EX_APPWINDOW, $WS_EX_TOOLWINDOW))
    GUISetBkColor (0xffffff)
    $imageBox = GUICtrlCreatePic ($imageFile, 0, 0, $width, $height)
    $progress = GUICtrlCreateProgress (0, $height, $width, 20)
    GUISetState ()

    [/autoit] [autoit][/autoit] [autoit]

    ;; Get image pixels ;;
    $dc = _WinAPI_GetDC ($GUI)
    $memDc = _WinAPI_CreateCompatibleDC ($dc)
    $bitmap = _WinAPI_CreateCompatibleBitmap ($dc, $width, $height)
    _WinAPI_SelectObject ($memDc, $bitmap)
    _WinAPI_BitBlt ($memDc, 0, 0, $width, $height, $dc, 0, 0, $SRCCOPY)
    $bits = DllStructCreate ("dword[" & ($width * $height) & "]")
    DllCall ("gdi32", "int", "GetBitmapBits", "ptr", $bitmap, "int", ($width * $height * 4), "ptr", DllStructGetPtr ($bits))
    GUICtrlDelete ($imageBox)

    [/autoit] [autoit][/autoit] [autoit]

    ;; Process the pixels ;;
    Dim $pixels[$width][$height]
    For $y = 0 To ($height - 1)
    For $x = 0 To ($width - 1)
    $index = ($y * $width) + $x
    $color = DllStructGetData ($bits, 1, $index)

    [/autoit] [autoit][/autoit] [autoit]

    $red = _ColorGetBlue ($color)
    $green = _ColorGetGreen ($color)
    $blue = _ColorGetRed ($color)
    $shade = ($red + $green + $blue) / 3
    If ($shade > $threshold) Then
    $color = 0xffffff
    $pixels[$x][$y] = 0
    Else
    $color = 0
    $pixels[$x][$y] = 1
    EndIf

    [/autoit] [autoit][/autoit] [autoit]

    DllStructSetData ($bits, 1, $color, $index)
    Next

    [/autoit] [autoit][/autoit] [autoit]

    DllCall ("gdi32", "int", "SetBitmapBits", "ptr", $bitmap, "int", ($width * $height * 4), "ptr", DllStructGetPtr ($bits))
    _WinAPI_BitBlt ($dc, 0, 0, $width, $height, $memDc, 0, 0, $SRCCOPY)
    GUICtrlSetData ($progress, ($y * 100) / $height)
    Next

    [/autoit] [autoit][/autoit] [autoit]

    _WinAPI_ReleaseDC ($GUI, $dc)
    GUIRegisterMsg ($WM_PAINT, "OnPaint")

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    ;; Ready to draw ;;
    TrayTip ("Pronto!", "Press F9 para draw. You can press F10 anytime to exit.", 10)
    HotKeySet ("{F9}", "Draw")
    HotKeySet ("{F10}", "Quit")

    [/autoit] [autoit][/autoit] [autoit]

    While 1
    Sleep (60000)
    WEnd

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    Func OnPaint ($hwndGUI, $msgID, $wParam, $lParam)
    Local $paintStruct = DllStructCreate ("hwnd hdc;int fErase;dword rcPaint[4];int fRestore;int fIncUpdate;byte rgbReserved[32]")

    [/autoit] [autoit][/autoit] [autoit]

    $dc = DllCall ("user32", "hwnd", "BeginPaint", "hwnd", $hwndGUI, "ptr", DllStructGetPtr ($paintStruct))
    $dc = $dc[0]

    [/autoit] [autoit][/autoit] [autoit]

    _WinAPI_BitBlt ($dc, 0, 0, $width, $height, $memDc, 0, 0, $SRCCOPY)

    [/autoit] [autoit][/autoit] [autoit]

    DllCall ("user32", "hwnd", "EndPaint", "hwnd", $hwndGUI, "ptr", DllStructGetPtr ($paintStruct))
    Return $GUI_RUNDEFMSG
    EndFunc

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    Func Draw ()
    $mouseCenter = MouseGetPos ()
    $x0 = $mouseCenter[0] - ($width / 2)
    $y0 = $mouseCenter[1] - ($height / 2)

    [/autoit] [autoit][/autoit] [autoit]

    ;; Move the mouse around the drawing perimeter ;;
    MouseMove ($x0, $y0)
    MouseMove ($x0 + $width, $y0)
    MouseMove ($x0 + $width, $y0 + $height)
    MouseMove ($x0, $y0 + $height)
    MouseMove ($x0, $y0)

    [/autoit] [autoit][/autoit] [autoit]

    ;; Draw all the areas ;;
    $stack = CreateStack (1000)
    For $y = 0 To ($height - 1)
    For $x = 0 To ($width - 1)
    If ($pixels[$x][$y] == 1) Then
    MouseMove ($x + $x0, $y + $y0, $speed)
    MouseDown ("primary")
    DrawArea ($stack, $x, $y, $x0, $y0)
    MouseUp ("primary")
    Else
    EndIf
    Next
    Next

    [/autoit] [autoit][/autoit] [autoit]

    ;; Reset the pixels statuses ;;
    For $y = 0 To ($height - 1) Step 1
    For $x = 0 To ($width - 1) Step 1
    If ($pixels[$x][$y] == 2) Then
    $pixels[$x][$y] = 1
    EndIf
    Next
    Next
    EndFunc

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    Func DrawArea (ByRef $stack, $x, $y, $x0, $y0)
    Local $path[8]
    Local $continue

    [/autoit] [autoit][/autoit] [autoit]

    $path = MakePath ($pathString)

    [/autoit] [autoit][/autoit] [autoit]

    While 1
    MouseMove ($x + $x0, $y + $y0, $speed)
    $pixels[$x][$y] = 2

    [/autoit] [autoit][/autoit] [autoit]

    If ($scramble) Then ScramblePath ($path)
    If ($rotate > 0) Then RotatePath ($path, $rotate)

    [/autoit] [autoit][/autoit] [autoit]

    ;;;;;;;;;;;;;;;;;;;
    ;; +---+---+---+ ;;
    ;; | 1 | 2 | 3 | ;;
    ;; +---+---+---+ ;;
    ;; | 4 | | 5 | ;;
    ;; +---+---+---+ ;;
    ;; | 6 | 7 | 8 | ;;
    ;; +---+---+---+ ;;
    ;;;;;;;;;;;;;;;;;;;

    [/autoit] [autoit][/autoit] [autoit]

    $continue = False
    For $i = 0 To 7
    Switch ($path[$i])
    Case 1
    If (($x > 0) And ($y > 0)) Then
    If ($pixels[$x - 1][$y - 1] == 1) Then
    Push ($stack, $x, $y)
    $x -= 1
    $y -= 1
    $continue = True
    ExitLoop
    EndIf
    EndIf

    [/autoit] [autoit][/autoit] [autoit]

    Case 2
    If ($y > 0) Then
    If ($pixels[$x][$y - 1] == 1) Then
    Push ($stack, $x, $y)
    $y -= 1
    $continue = True
    ExitLoop
    EndIf
    EndIf

    [/autoit] [autoit][/autoit] [autoit]

    Case 3
    If (($x > 0) And ($y < 0)) Then
    If ($pixels[$x + 1][$y - 1] == 1) Then
    Push ($stack, $x, $y)
    $x += 1
    $y -= 1
    $continue = True
    ExitLoop
    EndIf
    EndIf

    [/autoit] [autoit][/autoit] [autoit]

    Case 4
    If ($x > 0) Then
    If ($pixels[$x - 1][$y] == 1) Then
    Push ($stack, $x, $y)
    $x -= 1
    $continue = True
    ExitLoop
    EndIf
    EndIf

    [/autoit] [autoit][/autoit] [autoit]

    Case 5
    If ($x < ($width - 1)) Then
    If ($pixels[$x + 1][$y] == 1) Then
    Push ($stack, $x, $y)
    $x += 1
    $continue = True
    ExitLoop
    EndIf
    EndIf

    [/autoit] [autoit][/autoit] [autoit]

    Case 6
    If (($x < 0) And ($y > 0)) Then
    If ($pixels[$x - 1][$y + 1] == 1) Then
    Push ($stack, $x, $y)
    $x -= 1
    $y += 1
    $continue = True
    ExitLoop
    EndIf
    EndIf

    [/autoit] [autoit][/autoit] [autoit]

    Case 7
    If ($y < ($height - 1)) Then
    If ($pixels[$x][$y + 1] == 1) Then
    Push ($stack, $x, $y)
    $y += 1
    $continue = True
    ExitLoop
    EndIf
    EndIf

    [/autoit] [autoit][/autoit] [autoit]

    Case 8
    If (($x < ($width - 1)) And ($y < ($height - 1))) Then
    If ($pixels[$x + 1][$y + 1] == 1) Then
    Push ($stack, $x, $y)
    $x += 1
    $y += 1
    $continue = True
    ExitLoop
    EndIf
    EndIf
    EndSwitch
    Next
    If ($continue) Then ContinueLoop

    [/autoit] [autoit][/autoit] [autoit]

    If (Not Pop ($stack, $x, $y)) Then ExitLoop
    WEnd
    EndFunc

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    Func MakePath ($string)
    Return StringSplit ($string, "")
    EndFunc

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    Func ScramblePath (ByRef $path)
    Local $table = "12345678"
    Local $newPath[8]

    [/autoit] [autoit][/autoit] [autoit]

    For $i = 8 To 1 Step -1
    $next = StringMid ($table, Random (1, $i, 1), 1)
    $newPath[$i - 1] = Number ($next)
    $table = StringReplace ($table, $next, "")
    Next

    [/autoit] [autoit][/autoit] [autoit]

    $path = $newPath
    EndFunc

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    Func RotatePath (Byref $path, $places)
    If ($places == 0) Then
    Return $path
    Else
    For $i = 1 To Abs ($places)
    $temp = $path[7]
    $path[7] = $path[6]
    $path[6] = $path[5]
    $path[5] = $path[4]
    $path[4] = $path[3]
    $path[3] = $path[2]
    $path[2] = $path[1]
    $path[1] = $path[0]
    $path[0] = $temp
    Next
    EndIf
    EndFunc

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    Func CreateStack ($size)
    Dim $stack[$size + 1][2]
    $stack[0][0] = 0
    $stack[0][1] = $size
    Return $stack
    EndFunc

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    Func Push (ByRef $stack, $x, $y)
    $stack[0][0] += 1
    If ($stack[0][0] > $stack[0][1]) Then
    $stack[0][1] += 1000
    ReDim $stack[$stack[0][1] + 1][2]
    EndIf

    [/autoit] [autoit][/autoit] [autoit]

    $stack[$stack[0][0]][0] = $x
    $stack[$stack[0][0]][1] = $y
    EndFunc

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    Func Pop (ByRef $stack, ByRef $x, ByRef $y)
    If ($stack[0][0] < 1) Then
    Return False
    EndIf

    [/autoit] [autoit][/autoit] [autoit]

    $x = $stack[$stack[0][0]][0]
    $y = $stack[$stack[0][0]][1]

    [/autoit] [autoit][/autoit] [autoit]

    $stack[0][0] -= 1
    Return True
    EndFunc

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    Func Nothing ()
    EndFunc

    [/autoit] [autoit][/autoit] [autoit]

    Func Quit ()
    MouseUp ("primary")
    Exit
    EndFunc

    [/autoit]


    Muss mich da zwar noch durchkämpfen, aber ich stell mal auf gelöst - der DLL Call macht ja das gleiche wie mein PixelGetcolor. Nur 100000 mal schneller

  • Hier ein Beispiel, um ein Bild in Graustufen umzuwandeln (ist aus dem engl. Forum)!

    Spoiler anzeigen
    [autoit]


    ;http://www.autoitscript.com/forum/index.ph…ndpost&p=513472
    #Include <GDIPlus.au3>

    [/autoit] [autoit][/autoit] [autoit]

    _GDIPlus_Startup()

    [/autoit] [autoit][/autoit] [autoit]

    $img = FileOpenDialog("Select an image", @ScriptDir & "\", "Images (*.jpg;*.bmp;*.png;*.gif)", 1)

    [/autoit] [autoit][/autoit] [autoit]

    $hImage1 = _GDIPlus_ImageLoadFromFile($img)
    $hImage2 = _GDIPlus_ImageGreyscale($hImage1)
    $ext = StringMid($img, StringLen($img) -2)
    $sCLSID = _GDIPlus_EncodersGetCLSID ($ext)
    _GDIPlus_ImageSaveToFileEx($hImage2, StringMid($img, 1, StringLen($img) - 4) & "_grey." & $ext, $sCLSID)
    $iwx = _GDIPlus_ImageGetWidth($hImage2)
    $iwy = _GDIPlus_ImageGetHeight($hImage2)
    $hGUI = GUICreate("Convert image to greyscale by Siao", $iwx, $iwy)
    GUISetState()

    [/autoit] [autoit][/autoit] [autoit]

    $hGraphic = _GDIPlus_GraphicsCreateFromHWND ($hGUI)
    _GDIPlus_GraphicsDrawImageRect($hGraphic, $hImage2, 0, 0, $iwx, $iwy)

    [/autoit] [autoit][/autoit] [autoit]

    While GUIGetMsg() <> -3 * Sleep(50)
    WEnd

    [/autoit] [autoit][/autoit] [autoit]

    _GDIPlus_ImageDispose($hImage1)
    _GDIPlus_ImageDispose($hImage2)

    [/autoit] [autoit][/autoit] [autoit]

    _GDIPlus_ShutDown()
    Exit

    [/autoit] [autoit][/autoit] [autoit]

    ;; _GDIPlus_ImageGreyscale()
    ;; Creates a greyscale copy of Image object and returns its handle. To destroy it, use _GDIPlus_ImageDispose() or _GDIPlus_BitmapDispose()
    Func _GDIPlus_ImageGreyscale(Const ByRef $hImage)
    Local $tColorMatrix, $x, $hImgAttrib, $iW = _GDIPlus_ImageGetWidth($hImage), $iH = _GDIPlus_ImageGetHeight($hImage), $hGraphics, $hGraphics2, $hBitmap
    ;;create color matrix data
    $tColorMatrix = DllStructCreate("float[5];float[5];float[5];float[5];float[5]")
    ;greyscale values:
    $x = DllStructSetData($tColorMatrix, 1, 0.30, 1) * DllStructSetData($tColorMatrix, 1, 0.30, 2) * DllStructSetData($tColorMatrix, 1, 0.30, 3) * _
    DllStructSetData($tColorMatrix, 2, 0.59, 1) * DllStructSetData($tColorMatrix, 2, 0.59, 2) * DllStructSetData($tColorMatrix, 2, 0.59, 3) * _
    DllStructSetData($tColorMatrix, 3, 0.11, 1) * DllStructSetData($tColorMatrix, 3, 0.11, 2) * DllStructSetData($tColorMatrix, 3, 0.11, 3) * _
    DllStructSetData($tColorMatrix, 4, 1.00, 4) * DllStructSetData($tColorMatrix, 5, 1.00, 5)
    ;;create an image attributes object and update its color matrix
    $hImgAttrib = _GDIPlus_ImageAttributesCreate()
    _GDIPlus_ImageAttributesSetColorMatrix($hImgAttrib, 1, DllStructGetPtr($tColorMatrix))
    ;;copy image
    $hGraphics = _GDIPlus_ImageGetGraphicsContext($hImage)
    $hBitmap = _GDIPlus_BitmapCreateFromGraphics($iW, $iH, $hGraphics)
    $hGraphics2 = _GDIPlus_ImageGetGraphicsContext($hBitmap)
    ;;draw original into copy with attributes
    _GDIPlus_GraphicsDrawImageRectRectEx($hGraphics2, $hImage, 0, 0, $iW, $iH, 0, 0, $iW, $iH, 2, $hImgAttrib)
    ;;clean up
    _GDIPlus_GraphicsDispose($hGraphics)
    _GDIPlus_GraphicsDispose($hGraphics2)
    _GDIPlus_ImageAttributesDispose($hImgAttrib)

    [/autoit] [autoit][/autoit] [autoit]

    Return $hBitmap
    EndFunc

    [/autoit] [autoit][/autoit] [autoit]

    ;;;;; other GDIPlus wrappers ;;;;;

    [/autoit] [autoit][/autoit] [autoit]

    #cs
    _GDIPlus_ImageAttributesSetColorMatrix()
    Sets ColorMatrix of ImageAttributes object
    Parameters:
    $hImgAttrib = ImageAttributes object
    $iColorAdjustType = can be:
    ColorAdjustTypeDefault = 0
    ColorAdjustTypeBitmap = 1
    ColorAdjustTypeBrush = 2
    ColorAdjustTypePen = 3
    ColorAdjustTypeText = 4
    ColorAdjustTypeCount = 5
    ColorAdjustTypeAny (Reserved) = 6
    $pColorMatrix = pointer to ColorMatrix structure
    $pGrayMatrix = pointer to GreyMatrix structure
    $iColorMatrixFlags = can be:
    ColorMatrixFlagsDefault = 0
    ColorMatrixFlagsSkipGrays = 1
    ColorMatrixFlagsAltGray = 2
    Return value: True/False
    #ce
    Func _GDIPlus_ImageAttributesSetColorMatrix($hImgAttrib, $iColorAdjustType, $pColorMatrix = 0, $pGrayMatrix = 0, $iColorMatrixFlags = 0)
    Local $fEnable = 1, $aResult = DllCall($ghGDIPDll, "int", "GdipSetImageAttributesColorMatrix", "ptr",$hImgAttrib, "int",$iColorAdjustType, _
    "int",$fEnable, "ptr",$pColorMatrix, "ptr",$pGrayMatrix, "int",$iColorMatrixFlags)
    Return SetError($aResult[0], 0, $aResult[0] = 0)
    EndFunc

    [/autoit] [autoit][/autoit] [autoit]

    ;;Creates ImageAttributes object
    Func _GDIPlus_ImageAttributesCreate()
    Local $aResult = DllCall($ghGDIPDll, "int", "GdipCreateImageAttributes", "ptr*", 0)
    Return SetError($aResult[0], 0, $aResult[1])
    EndFunc

    [/autoit] [autoit][/autoit] [autoit]

    ;;Deletes ImageAttributes object
    Func _GDIPlus_ImageAttributesDispose($hImgAttrib)
    Local $aResult = DllCall($ghGDIPDll, "int", "GdipDisposeImageAttributes", "ptr", $hImgAttrib)
    Return SetError($aResult[0], 0, $aResult[0] = 0)
    EndFunc

    [/autoit] [autoit][/autoit] [autoit]

    ;; _GDIPlus_GraphicsDrawImageRectRectEx()
    ;; Same as _GDIPlus_GraphicsDrawImageRectRect(), but adds 1 optional parameter - $hImgAttrib (handle to ImageAttributes object)
    Func _GDIPlus_GraphicsDrawImageRectRectEx($hGraphics, $hImage, $iSrcX, $iSrcY, $iSrcWidth, $iSrcHeight, $iDstX, $iDstY, $iDstWidth, $iDstHeight, $iUnit = 2, $hImgAttrib = 0)
    Local $aResult = DllCall($ghGDIPDll, "int", "GdipDrawImageRectRectI", "hwnd", $hGraphics, "hwnd", $hImage, "int", $iDstX, "int", _
    $iDstY, "int", $iDstWidth, "int", $iDstHeight, "int", $iSrcX, "int", $iSrcY, "int", $iSrcWidth, "int", _
    $iSrcHeight, "int", $iUnit, "ptr", $hImgAttrib, "int", 0, "int", 0)
    Return SetError($aResult[0], 0, $aResult[0] = 0)
    EndFunc

    [/autoit]

    Gruß,
    UEZ

    PS: hatte das Speichern nicht richtig durchdacht :rolleyes:

    Auch am Arsch geht ein Weg vorbei...

    ¯\_(ツ)_/¯

    Einmal editiert, zuletzt von UEZ (15. Dezember 2009 um 23:12)

  • Hi,
    ja, habe eine relativ schnelle Lösung(en) im engl. Forum gepostet, Zedna meinte sogar, ich solle meine Beispiele mal zusammenfassen und im dortigen Example-Forum publik machen....na schaumamal....

    Man muß die Dateien nicht unbedingt "sichtbar" machen, die Operationen direkt in der Bitmap sind wesentlich schneller und auch unkomplizierter (m.E.) als GDI+ (obschon man auch schon bei GDI+ auf "fertige" Funktionen zurückgreifen kann.
    Ich habe Dein "Bild nach Schwarzweiß" mal als Beispiel verwendet:
    Mona Lisa downloaden und im scriptverzeichnis speichern

    Spoiler anzeigen
    [autoit]

    #include <GDIPlus.au3>
    #include <GDIPlusConstants.au3>
    #include <StructureConstants.au3>
    #include <WinAPI.au3>
    ; quick and dirty....
    Global $stride, $ptr, $pixeldata
    global $bitmapfile1, $width1, $height1, $stride1, $pbitmap1
    global $bitmapfile2, $width2, $height2, $stride2, $pbitmap2
    local $numberdiff = 0 ;number of differences between the 2 pics

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    $pic1 = "mona-lisa.jpg" ;the image....24bit per pixel, could be a JPG which you want to have gray
    $pic3 = "grey.bmp" ;a bitmapfile with the greyscale

    [/autoit] [autoit][/autoit] [autoit]

    $t=timerinit()
    _GDIPlus_Startup()
    $pixelstruct1 = getbmpdata($pic1, $width1, $height1, $stride1, $pbitmap1) ;get all data from file

    [/autoit] [autoit][/autoit] [autoit]

    $lenght = DllStructGetSize($pixelstruct1) ;get lenght of bitmapdata
    $pixelstruct3 = dllstructcreate("ubyte["&$lenght&"]")
    ;compare
    for $i=1 to $lenght step 3
    $B=dllstructgetdata($pixelstruct1,1,$i) ;Farbanteil B
    $G=dllstructgetdata($pixelstruct1,1,$i+1) ;Farbanteil G
    $R=dllstructgetdata($pixelstruct1,1,$i+2) ;Farbanteil R
    $grau=int(($b+$g+$R)/3)

    [/autoit] [autoit][/autoit] [autoit]

    dllstructsetdata($pixelstruct3,1,$grau,$i) ;write the difference into the difference-file, bottom-up isnt funny but we´ll mirror it later :o)
    dllstructsetdata($pixelstruct3,1,$grau,$i+1) ;write the difference into the difference-file, bottom-up isnt funny but we´ll mirror it later :o)
    dllstructsetdata($pixelstruct3,1,$grau,$i+2) ;write the difference into the difference-file, bottom-up isnt funny but we´ll mirror it later :o)
    next

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    $head=DllStructcreate("ubyte[54]")
    ;lets create a bitmapfile with the given data
    $Bmpheader = DllStructCreate("align 1;char BM[2];uint Size;uint res;uint Offset;uint BMHI;uint Width;uint Height;short Planes;short BPP;uint BIcomp;int SizeImg;uint reshor;uint resver;uint col;uint colused", dllstructgetptr($head)) ;struct of bytes = header of bitmap #1
    ;fill struct(bitmapheader) with data
    DllStructSetData($bmpheader,"BM","BM")
    DllStructSetData($bmpheader,"Size",54+$lenght)
    DllStructSetData($bmpheader,"Offset",54)
    DllStructSetData($bmpheader,"BMHI",40)
    DllStructSetData($bmpheader,"Width",$width1)
    DllStructSetData($bmpheader,"Height",-$height1) ;negativ because "bottom up"
    DllStructSetData($bmpheader,"Planes",1)
    DllStructSetData($bmpheader,"BPP",24)
    DllStructSetData($bmpheader,"BIcomp",0)
    DllStructSetData($bmpheader,"SizeImg",$lenght)

    [/autoit] [autoit][/autoit] [autoit]

    $header = dllstructgetdata($head,1) ;headerdata
    $pixeldata = stringtrimleft(DllStructGetData($pixelstruct3, 1),2) ;pixeldata
    $bitmap = $header&$pixeldata ;all together is the bitmap-file

    [/autoit] [autoit][/autoit] [autoit]

    $filehandle = FileOpen($pic3, 18) ;write file
    FileWrite($filehandle,BinaryToString($bitmap))
    FileClose($filehandle)

    [/autoit] [autoit][/autoit] [autoit]

    _GDIPlus_ImageDispose($pBitmap1) ;not in the function, because ImageDispose destroys the struct
    ;_GDIPlus_ImageDispose($pBitmap2)
    $m=timerdiff($t)/1000

    [/autoit] [autoit][/autoit] [autoit]

    ;lets have a look what we have done...
    GUICreate("Pic2Gray "&$width1&"x"&$height1&" = "&$width1*$Height1&" Pixel in "&int($m)&" Seconds => "&int($width1*$Height1/$m)&" Pixel/Second",800,500)
    GUICtrlCreatePic($pic1, 10, 10, 350, 350 / $width1 * $height1)
    GUICtrlCreatePic($pic3, 400, 10, 350, 350 / $width1* $height1)
    GUISetState()

    [/autoit] [autoit][/autoit] [autoit]

    Do
    Until GUIGetMsg() = -3

    [/autoit] [autoit][/autoit] [autoit]

    Func getbmpdata($bmpfile, ByRef $width, ByRef $height, ByRef $stride, Byref $pbitmap) ;returns a struct with the data of the pixel
    $pbitmap = _GDIPlus_BitmapCreateFromFile($bmpfile)
    ;_GDIPlus_BitmapLockBits gibt $tagGDIPBITMAPDATA-Struktur zurück
    $BitmapData = _GDIPlus_BitmapLockBits($pBitmap, 0, 0, _GDIPlus_ImageGetWidth($pBitmap), _GDIPlus_ImageGetHeight($pBitmap), $GDIP_ILMREAD, $GDIP_PXF24RGB)
    If @error Then MsgBox(0, "", "Error locking region " & @error)
    $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.
    $pixeldata = DllStructCreate("ubyte[" & (Abs($stride) * ($height)) & "]", $Scan0)
    $BMPData = DllStructGetData($pixeldata, 1)
    _WinAPI_DeleteObject($pbitmap)
    _GDIPlus_BitmapUnlockBits($pBitmap, $BmpData)
    ;_GDIPlus_ImageDispose($pBitmap) ;destroys the pixeldatastruct, have to be done at end of the script!
    return $pixeldata
    EndFunc ;==>getbmpdata

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit][/autoit]

    Das von UEZ gepostete Beispiel benutzt z.B. eins dieser in GDI+ "eingebauten" Features, in diesem Fall die Beeinflussung der Farben. Um aber in eine(r) Datei zu "malen" bzw einzelne Bytes zu lesen/beeinflussen muß man schauen, welche Funktion am besten "hinhaut".

    ciao
    Andy


    "Schlechtes Benehmen halten die Leute doch nur deswegen für eine Art Vorrecht, weil keiner ihnen aufs Maul haut." Klaus Kinski
    "Hint: Write comments after each line. So you can (better) see what your program does and what it not does. And we can see what you're thinking what your program does and we can point to the missunderstandings." A-Jay

    Wie man Fragen richtig stellt... Tutorial: Wie man Script-Fehler findet und beseitigt...X-Y-Problem

    2 Mal editiert, zuletzt von Andy (15. Dezember 2009 um 23:05)


  • Ich war so frei und habe dein Beispiel gegen das GDI+ laufen lassen -> deins 3s. und GDI+ 45ms!

    Gruß,
    UEZ

    Auch am Arsch geht ein Weg vorbei...

    ¯\_(ツ)_/¯

  • Vielen Dank für die Ausführlichen Hilfen und Beispiele !
    Leider werd ich daraus nicht wirklich schlau, was wohl an meiner Unkenntnis gegenüber DLL's liegt.
    Werde das aber auf jeden Fall näher unter die Lupe nehmen!

    Schade nur, dass so stark auf das Thema Graustufen, und so wenig auf wirkliches Monochrom (Also wirklich nur Zweifarbig) eingegangen wurde. Aber für letzteres hatte ich ja dann glücklicherweise schon eine Lösung gefunden (Siehe erster Post). Da das von mir gefundene Tool dann auch noch genau das macht, was ich mit meinem Skript vorhatte (nur 10x besser als ich es hinbekommen hätte), reicht mir auch das "gefundene" Skript.

    Trotzdem nochmals danke an alle !

  • Zitat

    Ich war so frei und habe dein Beispiel gegen das GDI+ laufen lassen -> deins 3s. und GDI+ 45ms!

    Genau deshalb habe ich ja geschrieben, daß man die in GDI+ "eingebauten" Funktionen für diese speziellen Sachen verwenden soll, WENN sie schneller sind...
    Die von mir geposteten Beispiele zeigen einen direkten Weg zu den Bitmapdaten und haben mit GDI+ nichts zu tun. Obwohl ich mir ehrlich gesagt mit GDI+ einen abgebrochen habe, einzelne Pixel oder Bereiche aus Bildern auszulesen, was aber wahrscheinlich auch daran liegt, daß eine Datei zu öffnen, die Pixeldaten in ein Array einzulesen und weiterzuverarbeiten wesentlich einfacher und auch schneller ist.

    Wir nehmen das Graustufenbild der Mona Lisa und suchen alle Pixel mit einer bestimmten "Farbe" um damit z.B. ein bisschen Steganographie zu machen. Dann wäre es nützlich, einen 1:1 Bildvergleich zu machen und/oder die geänderten Pixel zu finden. Das könnte man mit GDI+ und ein bisschen cleverem Bitblt auch versuchen, allerdings bekommt man so weder Position noch Farbe der Pixel, sondern hat wieder ein weiteres "DifferenzBild".
    Wie bekommt man Informationen aus verrauschten Bildern einer Webcam? Wie lese ich den "Text" per OCR aus einem Bild? Alles Anwendungen, bei denen man direkt auf die Rohdaten zugreifen muß.... und einem GDI+ i.d.R. sehr wenig bringt...

    Zitat

    Schade nur, dass so stark auf das Thema Graustufen, und so wenig auf wirkliches Monochrom (Also wirklich nur Zweifarbig) eingegangen wurde.

    Na ändere doch im von UEZ geposteten Script einfach die Parameter. Schwarz/weiß ist doch nur die extremste Form der Graustufen.
    Oder füge in meinem Script (habe extra eine Leerzeile gelassen^^) in Zeile 27 ein:

    [autoit]

    if $grau<128 then
    $grau = 0
    Else
    $grau=255
    endif

    [/autoit]
  • Hatte mal zu einer Hilfestellung ein Beispiel umgewandelt. Hier kann man schön verfolgen wie das Bild umgewandelt wird, also eher zu Demo-Zwecken zu verwenden. Man kann hier aussuchen nach welchem Farbanteil (R,G,B) das Schwarz-Weiß-Bild erzeugt wird.

    Spoiler anzeigen
    [autoit]

    #cs **************************************************************************

    [/autoit] [autoit][/autoit] [autoit]

    Ein Bild in schwarz weiß speichern und vergleichen

    [/autoit] [autoit][/autoit] [autoit]

    http://www.autoit.de/index.php?page…77121#post77121

    [/autoit] [autoit][/autoit] [autoit]

    #ce **************************************************************************

    [/autoit] [autoit][/autoit] [autoit]

    #include <GDIPlus.au3>
    #include <WindowsConstants.au3>
    #include <Color.au3>
    #include <WinAPI.au3>

    [/autoit] [autoit][/autoit] [autoit]

    $PATH = FileOpenDialog("Datei auswählen",@ScriptDir,"Bilder (*.bmp; *.jpg)",1)
    If @error Then Exit
    $CHOOSE = GUICreate("Wählen",100,60,-1,-1,0x16C80000)
    $COMBO = GUICtrlCreateCombo("",5,5,90,20)
    GUICtrlSetData($COMBO,"Rot-Anteil|Grün-Anteil|Blau-Anteil","Rot-Anteil")
    $SELECT = GUICtrlCreateButton("OK",5,30,90,20)
    GUISetState(@SW_SHOW,$CHOOSE)
    While 1
    $MSG = GUIGetMsg()
    If $MSG = $SELECT Then
    $CHANNEL = GUICtrlRead($COMBO)
    GUIDelete($CHOOSE)
    ExitLoop
    ElseIf $MSG = -3 Then
    Exit
    EndIf
    Sleep(15)
    WEnd

    [/autoit] [autoit][/autoit] [autoit]

    $SAVE = FileSaveDialog("Speichern",@ScriptDir,"Bild (*.jpg)",16,"Bitmap_" & $CHANNEL & ".JPG")
    If @error Then
    Exit
    Else
    If StringRight($SAVE, 4) <> ".JPG" Then $SAVE &= ".JPG"
    EndIf

    [/autoit] [autoit][/autoit] [autoit]

    _GDIPlus_Startup()
    $IMAGE = _GDIPlus_ImageLoadFromFile($PATH)
    $X = _GDIPlus_ImageGetWidth($IMAGE)
    $Y = _GDIPlus_ImageGetHeight($IMAGE)
    _GDIPlus_ImageDispose($IMAGE)

    [/autoit] [autoit][/autoit] [autoit]

    $GUI = GUICreate("SW-Maker",$X,$Y,-1,-1,0x80000000)
    GUISetBkColor(0xFFFFFF)
    $PICTURE = GUICtrlCreatePic($PATH,0,0,$X,$Y)
    GUISetState(@SW_SHOW,$GUI)

    [/autoit] [autoit][/autoit] [autoit]

    $DC = _WinAPI_GetDC($GUI)
    $C_DC = _WinAPI_CreateCompatibleDC($DC)
    $BITMAP = _WinAPI_CreateCompatibleBitmap($DC,$X,$Y)
    _WinAPI_SelectObject($C_DC,$BITMAP)
    _WinAPI_BitBlt ($C_DC,0,0,$X,$Y,$DC,0,0,$SRCCOPY)
    $BITS = DllStructCreate ("dword[" & ($X * $Y) & "]")
    DllCall ("gdi32", "int", "GetBitmapBits", "ptr", $BITMAP, "int", ($X * $Y * 4), "ptr", DllStructGetPtr ($BITS))
    GUICtrlDelete($PICTURE)

    [/autoit] [autoit][/autoit] [autoit]

    For $CY = 0 To ($Y - 1)
    For $CX = 0 To ($X - 1)
    $INDEX = ($CY * $X) + $CX
    $COLOR = DllStructGetData ($BITS,1, $INDEX)
    $RED = Hex(_ColorGetRed($COLOR),2)
    $GREEN = Hex(_ColorGetGreen($COLOR),2)
    $BLUE = Hex(_ColorGetBlue($COLOR),2)
    If $CHANNEL = "Rot-Anteil" Then
    $COLOR = "0x" &$RED&$RED&$RED
    ElseIf $CHANNEL = "Grün-Anteil" Then
    $COLOR = "0x"&$GREEN&$GREEN&$GREEN
    ElseIf $CHANNEL = "Blau-Anteil" Then
    $COLOR = "0x"&$BLUE&$BLUE&$BLUE
    EndIf
    DllStructSetData ($BITS,1,$COLOR,$INDEX)
    Next
    DllCall ("gdi32", "int", "SetBitmapBits", "ptr", $BITMAP, "int", ($X * $Y * 4), "ptr", DllStructGetPtr ($BITS))
    _WinAPI_BitBlt ($DC,0,0,$X,$Y,$C_DC,0,0,$SRCCOPY)
    Next
    $HIMAGE = _GDIPlus_BitmapCreateFromHBITMAP($BITMAP)
    _GDIPlus_ImageSaveToFile($HIMAGE,$SAVE)
    _WinAPI_DeleteObject($HIMAGE)
    _WinAPI_DeleteObject($BITMAP)
    _GDIPlus_Shutdown()
    _WinAPI_ReleaseDC($GUI,$DC)

    [/autoit]
  • Anmerkung: mit dem Benchmark wollte ich nur den Geschwindigkeitsunterschied darstellen und NICHT, dass dein Code irgendwie schlecht/schlechter ist als das GDI+ Beispiel!

    Je nach Anwendung kann man sich ja den entstprechenden Code aussuchen!

    Gruß,
    UEZ

    Auch am Arsch geht ein Weg vorbei...

    ¯\_(ツ)_/¯

  • Zitat

    Je nach Anwendung kann man sich ja den entstprechenden Code aussuchen!

    Allerdings, ich hatte den Wink schon richtig verstanden :D
    Das schöne an der Arbeit mit den structs ist, daß man die prospeed.dll ohne weiteres sofort einsetzen kann, das ist auch der einzige Grund, warum ich bisher den AutoIt-"Inlineassembler" nicht aktiviere. Gerade was den richtig schnellen Grafikkram betrifft, ist es besser, hier im Forum "den Ball ein wenig flach zu halten".
    Sonst werden die Jungs und Mädelz im "bösen" Forum wieder aufmerksam 8o, und ich bekomme wieder haufenweise PN´s nach Pixelsearch in "hiden fenstas" :rofl:

  • Allerdings, ich hatte den Wink schon richtig verstanden :D
    Das schöne an der Arbeit mit den structs ist, daß man die prospeed.dll ohne weiteres sofort einsetzen kann, das ist auch der einzige Grund, warum ich bisher den AutoIt-"Inlineassembler" nicht aktiviere. Gerade was den richtig schnellen Grafikkram betrifft, ist es besser, hier im Forum "den Ball ein wenig flach zu halten".
    Sonst werden die Jungs und Mädelz im "bösen" Forum wieder aufmerksam 8o, und ich bekomme wieder haufenweise PN´s nach Pixelsearch in "hiden fenstas" :rofl:

    AutoIt-"Inlineassembler" - klingt interessant! Hast du was für mich (Tutorials), womit ich einige Sachen in GDI+ beschleunigen kann? trancexx hat ja schon einige sehr interessante Beispiele mit Inline ASM gezeigt, nur mir fehlt ein wenig der Einstieg.
    Für Bots habe ich ehrlich gesagt auch kein Bock was zu machen - einfach uninteressant für mich!

    Danke,
    UEZ

    Auch am Arsch geht ein Weg vorbei...

    ¯\_(ツ)_/¯

  • es gibt 2 Möglichkeiten der Einbindung von Assemblercode:
    - trancexx (wie sollte es anders sein) hält es mit dem Motto der Frauen, je härter, je besser. Sie codet "zu Fuß", benutzt also keinen Assemblercode, sondern schreibt die Prozessorbefehle direkt per Bits und Bytes in den Speicher und setzt dann den Programmpointer auf diesen Code...crazy!

    Spoiler anzeigen
    [autoit]

    ; by trancexx
    #include <GUIConstantsEx.au3>
    #include <Memory.au3>

    [/autoit] [autoit][/autoit] [autoit]

    Opt("GUIOnEventMode", 1)

    [/autoit] [autoit][/autoit] [autoit]

    Global Const $STM_SETIMAGE = 370

    [/autoit] [autoit][/autoit] [autoit]

    Global Const $iWidth = 800
    Global Const $iHeight = 470

    [/autoit] [autoit][/autoit] [autoit]

    GUICreate("", $iWidth, $iHeight)
    GUISetOnEvent(-3, "_Quit")
    GUISetBkColor(0)

    [/autoit] [autoit][/autoit] [autoit]

    Global $hPic = GUICtrlCreatePic("", 0, 0, $iWidth, $iHeight)

    [/autoit] [autoit][/autoit] [autoit]

    Global $iSize = $iWidth * $iHeight
    Global $tBits = DllStructCreate("int[" & $iSize & "]")
    Global $pBits = DllStructGetPtr($tBits)

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    Global $hBitmap, $aCall, $iHMsg
    Global $hPicHandle = GUICtrlGetHandle($hPic)

    [/autoit] [autoit][/autoit] [autoit]

    Global $tRandom = DllStructCreate("dword")
    Global $pRandom = DllStructGetPtr($tRandom)

    [/autoit] [autoit][/autoit] [autoit]

    GUISetState()

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    Global $aRtlRandomEx = DllCall("kernel32.dll", "ptr", "GetProcAddress", "ptr", _WinAPI_GetModuleHandle("ntdll.dll"), "str", "RtlRandomEx")
    Global $pRtlRandomEx = $aRtlRandomEx[0]

    [/autoit] [autoit][/autoit] [autoit]

    Global $aRtlMoveMemory = DllCall("kernel32.dll", "ptr", "GetProcAddress", "ptr", _WinAPI_GetModuleHandle("kernel32.dll"), "str", "RtlMoveMemory")
    Global $pRtlMoveMemory = $aRtlMoveMemory[0]

    [/autoit] [autoit][/autoit] [autoit]

    Global $aSendMessageW = DllCall("kernel32.dll", "ptr", "GetProcAddress", "ptr", _WinAPI_GetModuleHandle("user32.dll"), "str", "SendMessageW")
    Global $pSendMessageW = $aSendMessageW[0]

    [/autoit] [autoit][/autoit] [autoit]

    Global $aDeleteObject = DllCall("kernel32.dll", "ptr", "GetProcAddress", "ptr", _WinAPI_GetModuleHandle("gdi32.dll"), "str", "DeleteObject")
    Global $pDeleteObject = $aDeleteObject[0]

    [/autoit] [autoit][/autoit] [autoit]

    Global $aCreateBitmap = DllCall("kernel32.dll", "ptr", "GetProcAddress", "ptr", _WinAPI_GetModuleHandle("gdi32.dll"), "str", "CreateBitmap")
    Global $pCreateBitmap = $aCreateBitmap[0]

    [/autoit] [autoit][/autoit] [autoit]

    Global $pRemoteCode = _MemVirtualAlloc(0, 512, $MEM_COMMIT, $PAGE_EXECUTE_READWRITE)

    [/autoit] [autoit][/autoit] [autoit]

    Local $tCodeBuffer = DllStructCreate("byte[512]", $pRemoteCode)

    [/autoit] [autoit][/autoit] [autoit]

    #Region Assemply
    DllStructSetData($tCodeBuffer, 1, _
    "0x" & _
    "33DB" & _ ; xor ebx, ebx
    "68" & SwapEndian($pRandom) & _ ; push $pRandom
    "B8" & SwapEndian($pRtlRandomEx) & _ ; mov eax, RtlRandomEx
    "FFD0" & _ ; call eax
    "8BCB" & _ ; mov ecx, ebx
    "69C9" & SwapEndian(4) & _ ; imul ecx, 4
    "81C1" & SwapEndian($pBits) & _ ; add ecx, $pBits
    "68" & SwapEndian(3) & _ ; push 3 bytes
    "68" & SwapEndian($pRandom) & _ ; push $pRandom
    "51" & _ ; push ecx
    "B8" & SwapEndian($pRtlMoveMemory) & _ ; mov eax, RtlMoveMemory
    "FFD0" & _ ; call eax
    "43" & _ ; inc ebx
    "81FB" & SwapEndian($iSize) & _ ; cmp ebx, $iSize; <- compare ebx with $iSize
    "75" & Hex(256 - 53, 2) & _ ; jne -53 bytes; <- this is saying go back and do it again if not equal
    "68" & SwapEndian($pBits) & _ ; push $pBits
    "68" & SwapEndian(32) & _ ; push BitsPerPel
    "68" & SwapEndian(1) & _ ; push Planes
    "68" & SwapEndian($iHeight) & _ ; push $iHeight
    "68" & SwapEndian($iWidth) & _ ; push $iWidth
    "B8" & SwapEndian($pCreateBitmap) & _ ; mov eax, CreateBitmap
    "FFD0" & _ ; call eax
    "50" & _ ; push eax
    "68" & SwapEndian(0) & _ ; push IMAGE_BITMAP
    "68" & SwapEndian($STM_SETIMAGE) & _ ; push STM_SETIMAGE
    "68" & SwapEndian($hPicHandle) & _ ; push $hPicHandle
    "B8" & SwapEndian($pSendMessageW) & _ ; mov eax, SendMessageW
    "FFD0" & _ ; call eax
    "50" & _ ; push eax
    "B8" & SwapEndian($pDeleteObject) & _ ; mov eax, DeleteObject
    "FFD0" & _ ; call eax
    "C3" _ ; ret
    )
    #EndRegion Assembly

    [/autoit] [autoit][/autoit] [autoit]

    ;While 1

    [/autoit] [autoit][/autoit] [autoit]

    #region Assembly

    [/autoit] [autoit][/autoit] [autoit]


    $t=timerinit()
    for $i=1 to 10
    DllCall("user32.dll", "int", "CallWindowProcW", _
    "ptr", $pRemoteCode, _
    "int", 0, _
    "int", 0, _
    "int", 0, _
    "int", 0)
    next
    #endregion Assembly
    $x=timerdiff($t)
    msgbox(0,0,$x)
    Sleep(10)
    while 1
    WEnd

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    Func SwapEndian($iValue)
    Return Hex(Binary($iValue))
    EndFunc ;==>SwapEndian

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    Func _Quit()
    Exit
    EndFunc ;==>_Quit

    [/autoit]

    - die zweite Möglichkeit ist "schön" :D
    Sprungmarken, eine "richtige" Assemblersyntax und andere feine Features sind in eine fertige Assembler-UDF eingebaut.

    Spoiler anzeigen
    [autoit]

    #include <ASM.au3>

    [/autoit] [autoit][/autoit] [autoit]

    ; Initial an asm object
    Global $Asm = AsmInit()

    [/autoit] [autoit][/autoit] [autoit]

    Demo1()
    Demo2()
    Demo3()
    Demo4()

    [/autoit] [autoit][/autoit] [autoit]

    Func Demo1()
    ; Demo 1: Using Parameters
    AsmReset($Asm)
    AsmAdd($Asm, "push ebp")
    AsmAdd($Asm, "mov ebp, esp")
    AsmAdd($Asm, "mov eax, [ebp + 08]")
    AsmAdd($Asm, "add eax, [ebp + 0c]")
    AsmAdd($Asm, "pop ebp")
    AsmAdd($Asm, "retn 8")
    ConsoleWrite(String(AsmGetBinary($Asm)) & @CRLF)
    $Ret = MemoryFuncCall("int", AsmGetPtr($Asm), "int", 1, "int", 2)
    MsgBox(0, "Demo 1: Using Parameters", "1 + 2 = " & $Ret[0])
    EndFunc

    [/autoit] [autoit][/autoit] [autoit]

    Func Demo2()
    ; Demo 2: Read Time-Stamp Counter
    AsmReset($Asm)
    AsmAdd($Asm, "push ebp")
    AsmAdd($Asm, "mov ebp, esp")
    AsmAdd($Asm, "rdtsc")
    AsmAdd($Asm, "mov ecx, [ebp + 08]")
    AsmAdd($Asm, "mov [ecx], edx")
    AsmAdd($Asm, "pop ebp")
    AsmAdd($Asm, "retn 4")
    ConsoleWrite(String(AsmGetBinary($Asm)) & @CRLF)
    $start=timerinit()
    $Ret = MemoryFuncCall("uint", AsmGetPtr($Asm), "uint*", 0)
    MsgBox(0, "Demo 2: Read Time-Stamp Counter",timerdiff($start)& " RDTSC = " & Hex($Ret[1]) & Hex($Ret[0], 8))
    Return Hex($Ret[1]) & Hex($Ret[0], 8)
    EndFunc

    [/autoit] [autoit][/autoit] [autoit]

    Func Demo3()
    ; Demo 3: Using Label
    AsmReset($Asm)
    AsmAdd($Asm, "mov eax, 0")
    AsmAdd($Asm, "mov ecx, 10")
    AsmAdd($Asm, "label:")
    AsmAdd($Asm, "inc eax")
    AsmAdd($Asm, "loop @label")
    AsmAdd($Asm, "ret")
    ConsoleWrite(String(AsmGetBinary($Asm)) & @CRLF)
    $Ret = MemoryFuncCall("int", AsmGetPtr($Asm))
    MsgBox(0, "Demo 3: Using Label", "loop label for " & $Ret[0] & " times")
    EndFunc

    [/autoit] [autoit][/autoit] [autoit]

    Func Demo4()
    ; Demo 4: Call AutoIt Func From Assembly
    $AutoItFunc = DllCallbackRegister("AutoItFunc", "int", "")
    AsmReset($Asm)
    AsmAdd($Asm, "call " & DllCallbackGetPtr($AutoItFunc))
    ;AsmAdd($Asm, "shl eax, 1")
    AsmAdd($Asm, "ret")
    ConsoleWrite(String(AsmGetBinary($Asm)) & @CRLF)
    $Ret = MemoryFuncCall("int", AsmGetPtr($Asm))
    MsgBox(0, "Demo 4: AutoIt Function", "BitShift return value of AutoItFunc: " & $Ret[0])
    DllCallbackFree($AutoItFunc)
    EndFunc

    [/autoit] [autoit][/autoit] [autoit]

    Func AutoItFunc()
    MsgBox(0, "AutoItFunc", "Called by Inline Assembly")
    Return 1230
    EndFunc

    [/autoit] [autoit][/autoit] [autoit]

    ; Release the asm object
    AsmExit($Asm)
    Exit

    [/autoit] [autoit][/autoit] [autoit][/autoit]


    Welche man letztendlich nutzt, bleibt jedem selbst überlassen, aber die ASM.au3 wäre mein Favorit.

  • Noch eine Anmerkung bzgl. Geschwindigkeit, die Lösung der ASM.au3 ist genauso schnell wie die "handcodierte". Irgend ein "Spezialist" hat die Ausführung der 3. Demo ausgestoppt und festgestellt, daß ein For $i=1 to 4: i+=1: next wesentlich schneller ist und darum sei die gesamte UDF langsam und somit Quatsch :cursing:
    Generell gibt es beim Aufruf von dll´s einen "overhead" an Befehlen um Variablen zu übergeben, Speicher anzufordern usw. Daß der overhead natürlich die Ausführung von den im Beispiel gebrachten 3-4 Prozessorbefehlen überwiegt, ist sonnenklar.
    Aber trancexx´ens Beispiel zeigt schonmal, wo geschwindigkeitsmäßig "der Hammer hängt" :rock:

  • Danke für die Info (ASM.au3 und die Demo dazu kenne ich bereits). Ich dachte er daran, wie man in ASM programmiert, aber ich werde mal googeln! ;)

    Danke,
    UEZ

    Auch am Arsch geht ein Weg vorbei...

    ¯\_(ツ)_/¯

  • Zitat

    Ich dachte er daran, wie man in ASM programmiert, aber ich werde mal googeln!

    Ja, viel Spass dabei^^. Das ist jetzt Ernst gemeint, es gibt wunderschöne Seiten zu diesem Thema! Wenn du dich auf die Befehlssätze vom 8088 beschränkst, ist das für den Anfang absolut ausreichend, 80286 und 80386 erweitern die Befehle nur um 16- bzw 32 Bitbefehle.
    Als Referenz für die Befehle hab ich hier noch einen uralten Schinken in Papierform, allerdings ist u.a. HIER eine sehr gute Online-Referenz. Passend dazu das sehr treffend geschriebene TUTORIAL

    Für den, der eine in Assembler geschriebene dll zur Grafikbearbeitung und auch die passende AutoIt-Implementation sucht, ist HIER ein weiteres Highlight. UNBEDINGT die AutoIt Megademo ansehen!! Ist vergraben im Verzeichnis Demos und Scources (AutoIt) und dort im Verzeichnis Megademo. Eine der schönsten AutoIt-Demos, die ich bisher gesehen habe, der Code zeigt auch, wie einfach die Funktionen anzusprechen sind.

  • Ja, viel Spass dabei^^. Das ist jetzt Ernst gemeint, es gibt wunderschöne Seiten zu diesem Thema! Wenn du dich auf die Befehlssätze vom 8088 beschränkst, ist das für den Anfang absolut ausreichend, 80286 und 80386 erweitern die Befehle nur um 16- bzw 32 Bitbefehle.
    Als Referenz für die Befehle hab ich hier noch einen uralten Schinken in Papierform, allerdings ist u.a. HIER eine sehr gute Online-Referenz. Passend dazu das sehr treffend geschriebene TUTORIAL

    Für den, der eine in Assembler geschriebene dll zur Grafikbearbeitung und auch die passende AutoIt-Implementation sucht, ist HIER ein weiteres Highlight. UNBEDINGT die AutoIt Megademo ansehen!! Ist vergraben im Verzeichnis Demos und Scources (AutoIt) und dort im Verzeichnis Megademo. Eine der schönsten AutoIt-Demos, die ich bisher gesehen habe, der Code zeigt auch, wie einfach die Funktionen anzusprechen sind.

    VIELEN DANK!

    UEZ

    Auch am Arsch geht ein Weg vorbei...

    ¯\_(ツ)_/¯