GDI+ Zeichnen und als Bild speichern.

  • Hab 2 Probleme mit GDIPlus. Ich möchte gern wie in Paint auf eine Fläche Zeichnen können und das anschließend als Bild abspeichern (Wenn möglich mit Transparenz).
    Als Bild abspeichern geht noch gar nicht, Zeichnen funktioniert, wenn aber der Stift (Pen) breiter als 1 Pixel ist sehen die gemalten Linien "zerrissen" aus.

    Weiß jemand eine Lösung?

    Code:

    Spoiler anzeigen
    [autoit]

    #include <WindowsConstants.au3>
    #include <WinAPI.au3>
    #Include <GDIPlus.au3>
    #Include <Misc.au3>
    #include <GUIConstantsEx.au3>

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

    Global $aButton[6]
    Global $dll = DllOpen("user32.dll")
    Global $Color = "0x000000"

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

    $gui = GUICreate("Test Windows regions", 150, 200, @DesktopWidth-170, 20, $WS_POPUP, $WS_EX_TOOLWINDOW)
    ;Left - Top - Width - Height
    $aButton[0] = GUICtrlCreateButton("1", 0, 0, 24, 24)
    $aButton[1] = GUICtrlCreateButton("2", 24, 0, 24, 24)
    $aButton[2] = GUICtrlCreateButton("", 48, 0, 24, 24)
    GUICtrlSetBkColor($aButton[2], $Color)
    $aButton[3] = GUICtrlCreateButton("4", 72, 0, 24, 24)
    $aButton[4] = GUICtrlCreateButton("Exit", 100, 0, 24, 24)
    $aButton[5] = GUICtrlCreatePic("", 0, 30, 150, 170, BitOR(-1, $WS_GROUP,$WS_CLIPSIBLINGS))
    GUISetState(@SW_SHOW)

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

    $pos = WinGetPos($gui)
    _GuiHole($gui, 0, 0, 150, 150)

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

    While 1
    $msg = GUIGetMsg()
    Switch $msg
    Case $aButton[4]
    Exit
    Case $aButton[0]
    MsgBox(0, '', 'Button1 geklickt')
    Case $aButton[1]
    MsgBox(0, '', 'Button2 geklickt')
    Case $aButton[2]
    $Color = _ChooseColor(2)
    If $Color <> -1 Then
    GUICtrlSetBkColor($aButton[2], $Color)
    EndIf
    Case $aButton[3]
    MsgBox(0, '', 'Button4 geklickt')
    Case $aButton[5]
    Draw()
    EndSwitch
    WEnd

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

    ;Thx an Bugfix
    Func _GuiHole($h_win, $i_x, $i_y, $i_sizew, $i_sizeh)
    Local $outer_rgn, $inner_rgn, $combined_rgn
    $combined_rgn = _WinAPI_CreateRectRgn(0, 0, 0, 0)
    _WinAPI_DeleteObject($outer_rgn)
    _WinAPI_DeleteObject($inner_rgn)
    _AddCtrlRegion($combined_rgn, $aButton)
    _WinAPI_SetWindowRgn($h_win, $combined_rgn)
    EndFunc ;==>_GuiHole

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

    Func _AddCtrlRegion($full_rgn, $ctrl_id)
    Local $ctrl_pos, $ctrl_rgn
    If IsArray($ctrl_id) Then
    For $i = 0 To UBound($ctrl_id) -1
    $ctrl_pos = ControlGetPos($gui, "", $ctrl_id[$i])
    $ctrl_rgn = _WinAPI_CreateRectRgn($ctrl_pos[0], $ctrl_pos[1], $ctrl_pos[0] + $ctrl_pos[2], $ctrl_pos[1] + $ctrl_pos[3])
    _WinAPI_CombineRgn($full_rgn, $full_rgn, $ctrl_rgn, $RGN_OR)
    _WinAPI_DeleteObject($ctrl_rgn)
    Next
    Else
    $ctrl_pos = ControlGetPos($gui, "", $ctrl_id)
    $ctrl_rgn = _WinAPI_CreateRectRgn($ctrl_pos[0], $ctrl_pos[1], $ctrl_pos[0] + $ctrl_pos[2], $ctrl_pos[1] + $ctrl_pos[3])
    _WinAPI_CombineRgn($full_rgn, $full_rgn, $ctrl_rgn, $RGN_OR)
    _WinAPI_DeleteObject($ctrl_rgn)
    EndIf
    EndFunc ;==>_AddCtrlRegion

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

    Func Draw()
    Local $hPen, $hGraphic, $MX, $MY, $MXOld, $MYOld, $WinPos
    Local $hBitmap

    _GDIPlus_Startup ()
    $hGraphic = _GDIPlus_GraphicsCreateFromHWND (WinGetHandle("Test Windows regions"))
    $hPen = _GDIPlus_PenCreate ('0xFF' & StringRight($Color,6),6)
    $WinPos=WinGetPos("Test Windows regions")
    ;_GDIPlus_PenSetDashCap($hPen, $GDIP_DASHCAPROUND)
    ;_GDIPlus_PenSetDashStyle($hPen, $GDIP_DASHSTYLEDASH)
    $MXOld=MouseGetPos(0) - $WinPos[0]
    $MYOld=MouseGetPos(1) - $WinPos[1]
    ; Loop until user exits
    While _IsPressed("01", $dll)
    $MX=MouseGetPos(0) - $WinPos[0]
    $MY=MouseGetPos(1) - $WinPos[1]
    _GDIPlus_GraphicsDrawLine ($hGraphic, $MXOld, $MYOld, $MX, $MY, $hPen)
    ;_GDIPlus_GraphicsDrawEllipse($hGraphic, $MX, $MY, 6, 6, $hPen) -> Fehler: Bild wird nach einiger Zeit gelöscht
    $MXOld=$MX
    $MYOld=$MY
    Wend

    ;ImageTest
    ;$hBitmap = _GDIPlus_BitmapCreateFromGraphics(150, 170, $hGraphic)
    ;$hImage = _GDIPlus_BitmapCreateFromHBITMAP ($hBitmap)
    ;$sEncoder = _GDIPlus_EncodersGetCLSID ("PNG")
    ;_GDIPlus_ImageSaveToFileEx($hBitmap, "C:\Test.png", $sEncoder)
    ;_GDIPlus_ImageSaveToFile($hBitmap, "C:\Test.bmp")

    ; Clean up resources
    _GDIPlus_PenDispose ($hPen)
    _GDIPlus_GraphicsDispose ($hGraphic)
    _GDIPlus_Shutdown ()
    EndFunc

    [/autoit]

    Einmal editiert, zuletzt von Bitboy (9. November 2009 um 13:27)

  • Hier eine Möglichkeit:

    Spoiler anzeigen
    [autoit]


    #include <WindowsConstants.au3>
    #include <WinAPI.au3>
    #Include <GDIPlus.au3>
    #Include <Misc.au3>
    #include <GUIConstantsEx.au3>

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

    Global $aButton[6]
    Global $dll = DllOpen("user32.dll")
    Global $Color = "0x000000"
    Global $bcolor = "0xEEEEEE"
    Global $hGraphic
    Global $hPen, $MX, $MY, $MXOld, $MYOld, $WinPos

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

    _GDIPlus_Startup ()

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

    $w = 150
    $h = 200

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

    $gui = GUICreate("Test Windows regions", $w, $h, @DesktopWidth-170, 20, $WS_POPUP, $WS_EX_TOOLWINDOW)
    $hGraphic = _GDIPlus_GraphicsCreateFromHWND (WinGetHandle($gui))
    $Bitmap = _GDIPlus_BitmapCreateFromGraphics($w, $h, $hGraphic) ;create bitmap
    $Buffer = _GDIPlus_ImageGetGraphicsContext($Bitmap) ;create buffer
    $hPen = _GDIPlus_PenCreate ('0xFF' & StringRight($Color,6),6)
    _GDIPlus_GraphicsClear($Buffer, $bcolor)
    $WinPos=WinGetPos($gui)

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

    ;Left - Top - Width - Height
    $aButton[0] = GUICtrlCreateButton("1", 0, 0, 24, 24, -1, $WS_EX_TOPMOST)
    $aButton[1] = GUICtrlCreateButton("2", 24, 0, 24, 24)
    $aButton[2] = GUICtrlCreateButton("", 48, 0, 24, 24)
    GUICtrlSetBkColor($aButton[2], $Color)
    $aButton[3] = GUICtrlCreateButton("4", 72, 0, 24, 24)
    $aButton[4] = GUICtrlCreateButton("Exit", 100, 0, 24, 24)
    $aButton[5] = GUICtrlCreatePic("", 0, 30, 150, 170, BitOR(-1, $WS_GROUP,$WS_CLIPSIBLINGS))
    GUISetState(@SW_SHOW)

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

    $pos = WinGetPos($gui)
    _GuiHole($gui, 0, 0, 150, 150)

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

    While 1
    $msg = GUIGetMsg()
    Switch $msg
    Case $aButton[4]
    ; Clean up resources
    _GDIPlus_PenDispose ($hPen)
    _GDIPlus_GraphicsDispose ($hGraphic)
    _GDIPlus_Shutdown ()
    Exit
    Case $aButton[0]
    _GDIPlus_ImageSaveToFileEx($Bitmap, @ScriptDir & "\Test.PNG", _GDIPlus_EncodersGetCLSID("PNG"))
    If Not @error Then
    MsgBox(0, '', 'Bild gespeichert nach ' & @ScriptDir & "\Test.bmp!")
    Else
    MsgBox(0, '', 'Error!')
    EndIf

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

    Case $aButton[1]
    MsgBox(0, '', 'Button2 geklickt')
    Case $aButton[2]
    $Color = _ChooseColor(2)
    If $Color <> -1 Then
    GUICtrlSetBkColor($aButton[2], $Color)
    EndIf
    Case $aButton[3]
    MsgBox(0, '', 'Button4 geklickt')
    Case $aButton[5]
    Draw()
    EndSwitch
    WEnd

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

    ;Thx an Bugfix
    Func _GuiHole($h_win, $i_x, $i_y, $i_sizew, $i_sizeh)
    Local $outer_rgn, $inner_rgn, $combined_rgn
    $combined_rgn = _WinAPI_CreateRectRgn(0, 0, 0, 0)
    _WinAPI_DeleteObject($outer_rgn)
    _WinAPI_DeleteObject($inner_rgn)
    _AddCtrlRegion($combined_rgn, $aButton)
    _WinAPI_SetWindowRgn($h_win, $combined_rgn)
    EndFunc ;==>_GuiHole

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

    Func _AddCtrlRegion($full_rgn, $ctrl_id)
    Local $ctrl_pos, $ctrl_rgn
    If IsArray($ctrl_id) Then
    For $i = 0 To UBound($ctrl_id) -1
    $ctrl_pos = ControlGetPos($gui, "", $ctrl_id[$i])
    $ctrl_rgn = _WinAPI_CreateRectRgn($ctrl_pos[0], $ctrl_pos[1], $ctrl_pos[0] + $ctrl_pos[2], $ctrl_pos[1] + $ctrl_pos[3])
    _WinAPI_CombineRgn($full_rgn, $full_rgn, $ctrl_rgn, $RGN_OR)
    _WinAPI_DeleteObject($ctrl_rgn)
    Next
    Else
    $ctrl_pos = ControlGetPos($gui, "", $ctrl_id)
    $ctrl_rgn = _WinAPI_CreateRectRgn($ctrl_pos[0], $ctrl_pos[1], $ctrl_pos[0] + $ctrl_pos[2], $ctrl_pos[1] + $ctrl_pos[3])
    _WinAPI_CombineRgn($full_rgn, $full_rgn, $ctrl_rgn, $RGN_OR)
    _WinAPI_DeleteObject($ctrl_rgn)
    EndIf
    EndFunc ;==>_AddCtrlRegion

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

    Func Draw()
    ;_GDIPlus_PenSetDashCap($hPen, $GDIP_DASHCAPROUND)
    ;_GDIPlus_PenSetDashStyle($hPen, $GDIP_DASHSTYLEDASH)
    $MXOld=MouseGetPos(0) - $WinPos[0]
    $MYOld=MouseGetPos(1) - $WinPos[1] - 24 ;- Knopf Höhe
    ; Loop until user exits
    While _IsPressed("01", $dll)
    $MX=MouseGetPos(0) - $WinPos[0]
    $MY=MouseGetPos(1) - $WinPos[1] - 24
    _GDIPlus_GraphicsDrawLine ($Buffer, $MXOld, $MYOld, $MX, $MY, $hPen)
    _GDIPlus_GraphicsDrawImageRect($hGraphic, $Bitmap, 0, 24, $w, $h)
    ;_GDIPlus_GraphicsDrawEllipse($hGraphic, $MX, $MY, 6, 6, $hPen) -> Fehler: Bild wird nach einiger Zeit gelöscht
    $MXOld=$MX
    $MYOld=$MY
    Wend

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

    ;ImageTest
    ;$hBitmap = _GDIPlus_BitmapCreateFromGraphics(150, 170, $hGraphic)
    ;$hImage = _GDIPlus_BitmapCreateFromHBITMAP ($hBitmap)
    ;$sEncoder = _GDIPlus_EncodersGetCLSID ("PNG")
    ;_GDIPlus_ImageSaveToFileEx($hBitmap, "C:\Test.png", $sEncoder)
    ;_GDIPlus_ImageSaveToFile($hBitmap, "C:\Test.bmp")

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

    EndFunc

    [/autoit]

    Kopf 1 speichert das Bild.

    An der Transparentfunktion arbeite ich noch dran :P

    Gruß,
    UEZ

    Auch am Arsch geht ein Weg vorbei...

    ¯\_(ツ)_/¯

    Einmal editiert, zuletzt von UEZ (5. November 2009 um 13:47)

  • Klasse! Werde ich mir ganz in Ruhe ansehen um es auch zu verstehen.

    Dafür, dass die Zeichnung so "zerrissen" aussieht hatte ich auf der Arbeit selber noch ne Lösung gefunden, nur leider vergessen mir zu notieren. werde ich dann am Montag nachreichen.

  • Mann muss die Zeichnung "Doppelt" machen:

    $Brush = _GDIPlus_BrushCreateSolid('0xFF' & StringRight($Color,6))
    ...
    _GDIPlus_GraphicsFillEllipse($backbuffer, $MX-($PenWidth/2), $MY-($PenWidth/2), $PenWidth, $PenWidth, $Brush)