#include <WindowsConstants.au3>
#include <GUIConstantsEx.au3>
#include <GDIPlus.au3>
#include <Color.au3>
#include <Misc.au3>

Global $iWidth, $iHeight, $Count = 0, $CurSel = 0
Global $aHistory[50]

Global $hWnd = GUICreate("AutoIt - Paint", 200, 30)
$Menu_File = GUICtrlCreateMenu("&Datei")
$Menu_Effects = GUICtrlCreateMenu("&Effekte")
$Menu_Edit = GUICtrlCreateMenu("&Bearbeiten")
$Open = GUICtrlCreateMenuItem("&Öffnen", $Menu_File)
$Save = GUICtrlCreateMenuItem("&Speichern", $Menu_File)
$Invert = GUICtrlCreateMenuItem("&Farben invertieren", $Menu_Effects)
$GrayScale = GUICtrlCreateMenuItem("&Graustufen", $Menu_Effects)
$BlackWhite = GUICtrlCreateMenuItem("&Schwarzweiß", $Menu_Effects)
$ColorIt = GUICtrlCreateMenuItem("&Färben", $Menu_Effects)
$Undo = GUICtrlCreateMenuItem("&Rückgängig", $Menu_Edit)
$Redo = GUICtrlCreateMenuItem("&Wiederholen", $Menu_Edit)
GUISetState()
GUIRegisterMsg($WM_PAINT, "WM_PAINT")

_GDIPlus_Startup()
$hGraphic = _GDIPlus_GraphicsCreateFromHWND($hWnd)

While 1
	$nMsg = GUIGetMsg()
	Switch $nMsg
		Case $GUI_EVENT_CLOSE
			_Exit()
		Case $GUI_EVENT_RESTORE
			WM_PAINT()
		Case $Open
			_Open()
		Case $Save
			_Save()
		Case $Invert
			_Invert()
		Case $GrayScale
			_GrayScale()
		Case $BlackWhite
			_BlackWhite()
		Case $ColorIt
			_ColorIt()
		Case $Undo
			If $CurSel <> 1 Then $CurSel -= 1
			WM_PAINT()
		Case $Redo
			If $CurSel <> $Count Then $CurSel += 1
			WM_PAINT()
	EndSwitch
WEnd

Func _Invert()
	$Count += 1
	$aHistory[$Count] = _GDIPlus_BitmapCloneArea($aHistory[$CurSel], 0, 0, $iWidth, $iHeight)
	$BitmapData = _GDIPlus_BitmapLockBits($aHistory[$Count], 0, 0, $iWidth, $iHeight, BitOR($GDIP_ILMREAD, $GDIP_ILMWRITE), $GDIP_PXF32RGB)
	$Scan = DllStructGetData($BitmapData, "Scan0")
	$Stride = DllStructGetData($BitmapData, "Stride")

	ProgressOn("ColorInvert", "Fortschritt:", "Pixel werden gescannt...")
	For $iY = 0 To $iHeight - 1
		For $iX = 0 To $iWidth - 1
			$PixelData = DllStructCreate("dword", $Scan + ($iY * $Stride) + ($iX * 4))
			$Color = DllStructGetData($PixelData, 1)
			DllStructSetData($PixelData, 1, BitOR(255 - _ColorGetRed($Color), BitShift(255 - _ColorGetGreen($Color), -8), BitShift(255 - _ColorGetBlue($Color), -16)))
		Next
		ProgressSet($iY * 100 / ($iHeight - 1))
	Next
	ProgressOff()
	_GDIPlus_BitmapUnlockBits($aHistory[$Count], $BitmapData)
	$CurSel = $Count
	WM_PAINT()
EndFunc   ;==>_Invert

Func _GrayScale()
	$Count += 1
	$aHistory[$Count] = _GDIPlus_BitmapCloneArea($aHistory[$CurSel], 0, 0, $iWidth, $iHeight)
	$BitmapData = _GDIPlus_BitmapLockBits($aHistory[$Count], 0, 0, $iWidth, $iHeight, BitOR($GDIP_ILMREAD, $GDIP_ILMWRITE), $GDIP_PXF32RGB)
	$Scan = DllStructGetData($BitmapData, "Scan0")
	$Stride = DllStructGetData($BitmapData, "Stride")

	ProgressOn("GrayScale", "Fortschritt:", "Pixel werden gescannt...")
	For $iY = 0 To $iHeight - 1
		For $iX = 0 To $iWidth - 1
			$PixelData = DllStructCreate("dword", $Scan + ($iY * $Stride) + ($iX * 4))
			$Color = DllStructGetData($PixelData, 1)
			$Color = _ColorGetRed($Color) * 0.3 + _ColorGetGreen($Color) * 0.59 + _ColorGetBlue($Color) * 0.11
			DllStructSetData($PixelData, 1, BitOR($Color, BitShift($Color, -8), BitShift($Color, -16)))
		Next
		ProgressSet($iY * 100 / ($iHeight - 1))
	Next
	ProgressOff()
	_GDIPlus_BitmapUnlockBits($aHistory[$Count], $BitmapData)
	$CurSel = $Count
	WM_PAINT()
EndFunc   ;==>_GrayScale

Func _BlackWhite()
	$Count += 1
	$aHistory[$Count] = _GDIPlus_BitmapCloneArea($aHistory[$CurSel], 0, 0, $iWidth, $iHeight)
	$Max = InputBox("GrayScale", "Schwellenwert von 0-255: ")
	$BitmapData = _GDIPlus_BitmapLockBits($aHistory[$Count], 0, 0, $iWidth, $iHeight, BitOR($GDIP_ILMREAD, $GDIP_ILMWRITE), $GDIP_PXF32RGB)
	$Scan = DllStructGetData($BitmapData, "Scan0")
	$Stride = DllStructGetData($BitmapData, "Stride")

	ProgressOn("BlackWhite", "Fortschritt:", "Pixel werden gescannt...")
	For $iY = 0 To $iHeight - 1
		For $iX = 0 To $iWidth - 1
			$PixelData = DllStructCreate("dword", $Scan + ($iY * $Stride) + ($iX * 4))
			$Color = DllStructGetData($PixelData, 1)
			$Color = _ColorGetRed($Color) + _ColorGetGreen($Color) + _ColorGetBlue($Color) / 3
			If $Color >= $Max Then
				$Color = 0xFFFFFF
			Else
				$Color = 0x000000
			EndIf
			DllStructSetData($PixelData, 1, BitOR(_ColorGetRed($Color), BitShift(_ColorGetGreen($Color), -8), BitShift(_ColorGetBlue($Color), -16)))
		Next
		ProgressSet($iY * 100 / ($iHeight - 1))
	Next
	ProgressOff()
	_GDIPlus_BitmapUnlockBits($aHistory[$Count], $BitmapData)
	$CurSel = $Count
	WM_PAINT()
EndFunc   ;==>_BlackWhite

Func _ColorIt()
	$Count += 1
	$aHistory[$Count] = _GDIPlus_BitmapCloneArea($aHistory[$CurSel], 0, 0, $iWidth, $iHeight)
	$hBuffer = _GDIPlus_ImageGetGraphicsContext($aHistory[$Count])
	$Color = _ChooseColor(2)
	$Color = "0x" & Hex(InputBox("Intensität", "Intensität des Farbfilters von 0-255: "), 2) & StringTrimLeft($Color, 2)
	$hBrush = _GDIPlus_BrushCreateSolid($Color)
	_GDIPlus_GraphicsFillRect($hBuffer, 0, 0, $iWidth, $iHeight, $hBrush)
	_GDIPlus_BrushDispose($hBrush)
	_GDIPlus_GraphicsDispose($hBuffer)
	$CurSel = $Count
	WM_PAINT()
EndFunc   ;==>_ColorIt

Func _Open()
	$sFilePath = FileOpenDialog("Datei auswählen", @ScriptDir, "Bilder (*.jpg;*.jpeg;*.png;*.bmp;*.gif)", 3)
	If @error Or $sFilePath = "" Then Return
	$Count += 1
	$aHistory[$Count] = _GDIPlus_BitmapCreateFromFile($sFilePath)
	$iWidth = _GDIPlus_ImageGetWidth($aHistory[$Count])
	$iHeight = _GDIPlus_ImageGetHeight($aHistory[$Count])
	$Pos = WinGetPos($hWnd)
	WinMove($hWnd, "", $Pos[0], $Pos[1], $iWidth + 7, $iHeight + 46)
	_GDIPlus_GraphicsDispose($hGraphic)
	$hGraphic = _GDIPlus_GraphicsCreateFromHWND($hWnd)
	$CurSel = $Count
	WM_PAINT()
EndFunc   ;==>_Open

Func _Save()
	$sFileDest = FileSaveDialog("Speichern unter", @ScriptDir, "Bilder (*.jpg;*.jpeg;*.png;*.bmp;*.gif)", 18)
	If @error Or $sFileDest = "" Then Return
	$sExt = StringTrimLeft($sFileDest, StringInStr($sFileDest, ".", 0, -1))
	If Not ($sExt = "jpg" Or $sExt = "jpeg" Or $sExt = "png" Or $sExt = "bmp" Or $sExt = "gif" Or $sExt = "jpg\" Or $sExt = "jpeg\" Or $sExt = "png\" Or $sExt = "bmp\" Or $sExt = "gif\") Then Return MsgBox(16, "Fehler", "Bitte gültige Dateiendung angeben")
	_GDIPlus_ImageSaveToFile($aHistory[$CurSel], $sFileDest)
EndFunc   ;==>_Save

Func _Exit()
	For $i = 0 To $Count
		_GDIPlus_BitmapDispose($aHistory[$i])
	Next
	_GDIPlus_GraphicsDispose($hGraphic)
	_GDIPlus_Shutdown()
	Exit
EndFunc   ;==>_Exit

Func WM_PAINT()
	_GDIPlus_GraphicsDrawImageRect($hGraphic, $aHistory[$CurSel], 0, 0, $iWidth, $iHeight)
EndFunc   ;==>WM_PAINT
