Hey Autoitte,
ich komme mal direkt auf den Punkt:
Weiß einer von euch wie man eine HBITMAP variable, in der ich vorher mit _GDIPlus_ImageLoadFromFile(),
die Farben in dieser Bitmap umkehren kann?
Bitmap invertieren
-
- [ offen ]
-
Xyron -
23. Dezember 2010 um 16:27 -
Geschlossen -
Erledigt
-
-
Du solltest also entweder jeden Pixel einzeln ändern (mit GDIP.au3, BitmapSetPixel) oder mit UnlockBits die Pixel im Speichern ändern
PS:
GDI+ hat Bitmaps, GDI hat HBITMAPs -
Hier mal ein beispiel mit einer FarbMatrix ;).
Spoiler anzeigen
[autoit]#include <GUIConstants.au3>
[/autoit] [autoit][/autoit] [autoit]
#include <GDIP.au3>$hWnd = GUICreate("Inverted Bitmap by name22 (autoit.de)", 600, 400)
[/autoit] [autoit][/autoit] [autoit]
GUISetState()_GDIPlus_Startup()
[/autoit] [autoit][/autoit] [autoit]$hGraphic = _GDIPlus_GraphicsCreateFromHWND($hWnd)
[/autoit] [autoit][/autoit] [autoit]
$hInvIA = _GDIPlus_ImageAttributesCreate()$hImage = _GDIPlus_ImageLoadFromFile(FileOpenDialog("Bild auswählen", @ScriptDir, "All Images (*.*)"))
[/autoit] [autoit][/autoit] [autoit]
$aImageDim = _GDIPlus_ImageGetDimension($hImage)$tColorMatrix = _GDIPlus_ColorMatrixCreateNegative()
[/autoit] [autoit][/autoit] [autoit]
$pColorMatrix = DllStructGetPtr($tColorMatrix)_GDIPlus_ImageAttributesSetColorMatrix($hInvIA, 0, True, $pColorMatrix)
[/autoit] [autoit][/autoit] [autoit]_GDIPlus_GraphicsDrawImageRectRectIA($hGraphic, $hImage, 0, 0, $aImageDim[0], $aImageDim[1], 0, 0, 600, 400, $hInvIA)
[/autoit] [autoit][/autoit] [autoit]While GUIGetMsg() <> $GUI_EVENT_CLOSE
[/autoit] [autoit][/autoit] [autoit]
WEnd_GDIPlus_GraphicsDispose($hGraphic)
[/autoit]
_GDIPlus_ImageAttributesDispose($hInvIA)
_GDIPlus_ImageDispose($hImage)
_GDIPlus_Shutdown()
Das ist wesentlich schneller als die Pixel mit BitmapLockBits o.Ä. zu bearbeiten.
Allerdings wird dazu noch die GDIP.au3 benötigt die hier irgendwo im Forum herumschwirrt . -
eine Steilvorlage für Assemblerprogrammierer (oder die, die es werden wollen^^)
Invertieren heisst auf Bitmapbearbeiterisch nämlich XOR 0xFFFFFF
Das geht natürlich auch Pixel für Pixel in AutoIt, oder aber in Assembler
per XOR kann man nämlich direkt Speicherzellen bearbeiten (in diesem Fall invertieren)
XOR [Speicher],0xFFFFFF
invertiert somit das Pixel. Mit das einfachste, was man in Assembler machen kannSpoiler anzeigen
[autoit];#include <AssembleIt.au3>
[/autoit] [autoit][/autoit] [autoit]
#include <GDIPlus.au3>_GDIPlus_Startup()
[/autoit] [autoit][/autoit] [autoit]
$file = FileOpenDialog("Grafikdatei öffnen", @ScriptDir, "Bilder (*.jpg;*.bmp;*.png)")
If @error Then Exit
$hBitmap = _GDIPlus_BitmapCreateFromFile($file)
$iWidth = _GDIPlus_ImageGetWidth($hBitmap)
$iHeight = _GDIPlus_ImageGetHeight($hBitmap)$hBitmapData = _GDIPlus_BitmapLockBits($hBitmap, 0, 0, $iWidth, $iHeight, BitOR($GDIP_ILMREAD, $GDIP_ILMWRITE), $GDIP_PXF32RGB)
[/autoit] [autoit][/autoit] [autoit]
$Scan = DllStructGetData($hBitmapData, "Scan0") ;Pointer auf bitmapdaten(Pixel);$ret=_AssembleIt("ptr","_invertieren","ptr", $scan, "int", $iWidth * $iHeight) ;ptr als Rückgabe, um die hexzahlen schön zu sehen
[/autoit] [autoit][/autoit] [autoit]
;oder
Global $tCodeBuffer = DllStructCreate("byte[23]") ;reserve Memory for opcodes
DllStructSetData($tCodeBuffer, 1, "0x8B7424048B4C24088136FFFFFF0083C60483E90177F2C3") ;write opcodes into memory
$ret = DllCall("user32.dll", "ptr", "CallWindowProcW", "ptr", DllStructGetPtr($tCodeBuffer), "ptr", $Scan, "int", $iWidth * $iHeight, "int", 0, "int", 0)_GDIPlus_BitmapUnlockBits($hBitmap, $hBitmapData)
[/autoit] [autoit][/autoit] [autoit]
_GDIPlus_ImageSaveToFile($hBitmap, "invert.jpg")ShellExecute("invert.jpg")
[/autoit] [autoit][/autoit] [autoit][/autoit] [autoit];~ Func _invertieren()
[/autoit] [autoit][/autoit] [autoit]
;~ _("use32") ;sollte immer eingesetzt werden!;~ _("mov esi,dword[esp+4]") ;Startadresse Bitmapdaten (Pixel)
[/autoit] [autoit][/autoit] [autoit]
;~ _("mov ecx,dword[esp+8]") ;anzahl Pixel;~ _("_schleife:") ;so lange, bis ecx=0
[/autoit] [autoit][/autoit] [autoit][/autoit]
;~ _("xor dword[esi],0xFFFFFF") ;Pixel invertieren
;~ _("add esi,4") ;adresse nächstes Pixel
;~ _("sub ecx,1") ;schleifendurchgang
;~ _("ja _schleife") ;so lange, bis ecx=0
;~ _("ret ")
;~ EndFunc ;==>_invertierenGeht auch bissl kürzer, aber so ist es verständlicher
/EDIT/ Funktioniert das so eigentlich auch in 64Bit BS?
-
- Offizieller Beitrag
Funktioniert das so eigentlich auch in 64Bit BS?
Nein, das Skript führt zu einem Absturz von AutoIt (Win7, 64 Bit).
Als 32Bit funktioniert es. -
Danke Oscar, liegt wohl daran, dass es bei 64Bit zwei der "user.dll" gibt....und ich die "falsche" benutze
-
- Offizieller Beitrag
Wenn ich den Pfad auf "c:\Windows\SysWOW64\user32.dll" ändere, dann stürzt AutoIt nicht ab, aber das Bild wird auch nicht invertiert.
Es wird zwar ein Bild "invert.jpg" erstellt und angezeigt, aber dort sind die Farben nicht invertiert. -
Ich seh schon, wird Zeit, dass ich mir mal ein 64Bit BS besorge....thx fürs Testen jedenfalls!
-
Sieht alles super aus ,
aber...
jetzt kommt die schwierigkeit:
ich möchte ein Bild auf mein Desktop malen, welches nur schwarz enthält (.png)
Diese ist ein Fadenkreuz und im Anhang
Es sollte dann immer sichtbar sein//Edit
Das Bild sollte nicht Flackern, also sollte es in einem Gui sein. Eingebunden hab ich es bisher immer mit dieser Funktion:Spoiler anzeigen
[autoit]Func SetBitmap($hGUI, $hImage, $iOpacity) ; lade hintergrundbild und mache den hintergrund transparent Local $hScrDC, $hMemDC, $hBitmap, $hOld, $pSize, $tSize, $pSource, $tSource, $pBlend, $tBlend
[/autoit]
$hScrDC = _WinAPI_GetDC(0) $hMemDC = _WinAPI_CreateCompatibleDC($hScrDC) $hBitmap = _GDIPlus_BitmapCreateHBITMAPFromBitmap($hImage) $hOld = _WinAPI_SelectObject($hMemDC, $hBitmap) $tSize = DllStructCreate($tagSIZE) $pSize = DllStructGetPtr($tSize) DllStructSetData($tSize, "X", _GDIPlus_ImageGetWidth($hImage)) DllStructSetData($tSize, "Y", _GDIPlus_ImageGetHeight($hImage)) $tSource = DllStructCreate($tagPOINT) $pSource = DllStructGetPtr($tSource) $tBlend = DllStructCreate($tagBLENDFUNCTION) $pBlend = DllStructGetPtr($tBlend) DllStructSetData($tBlend, "Alpha", $iOpacity) DllStructSetData($tBlend, "Format", $AC_SRC_ALPHA) _WinAPI_UpdateLayeredWindow($hGUI, $hScrDC, 0, $pSize, $hMemDC, $pSource, 0, $pBlend, $ULW_ALPHA) _WinAPI_ReleaseDC(0, $hScrDC) _WinAPI_SelectObject($hMemDC, $hOld) _WinAPI_DeleteObject($hBitmap) _WinAPI_DeleteDC($hMemDC)EndFunc -
Invertieren heisst auf Bitmapbearbeiterisch nämlich XOR 0xFFFFFF
Da bin ich bei meinem ASM-Inverter nicht drauf gekommen Ich hab jeden Byte einzeln 255- invertiert Muss ich direkt mal ändern -
Zitat
Da bin ich bei meinem ASM-Inverter nicht drauf gekommen
Tröste dich, ich hab auch erst von jedem Byte 255 abgezogen
-
Als reiner AutoItcode, bissl langsamer
Spoiler anzeigen
[autoit]#include <GDIPlus.au3>
[/autoit] [autoit][/autoit] [autoit]_GDIPlus_Startup()
[/autoit] [autoit][/autoit] [autoit]
$file = FileOpenDialog("Grafikdatei öffnen", @ScriptDir, "Bilder (*.jpg;*.bmp;*.png)")
If @error Then Exit
$hBitmap = _GDIPlus_BitmapCreateFromFile($file)
$iWidth = _GDIPlus_ImageGetWidth($hBitmap)
$iHeight = _GDIPlus_ImageGetHeight($hBitmap)$hBitmapData = _GDIPlus_BitmapLockBits($hBitmap, 0, 0, $iWidth, $iHeight, BitOR($GDIP_ILMREAD, $GDIP_ILMWRITE), $GDIP_PXF32RGB)
[/autoit] [autoit][/autoit] [autoit]
$Scan = DllStructGetData($hBitmapData, "Scan0") ;Pointer auf bitmapdaten(Pixel)
$struct = DllStructCreate("dword [" & $iWidth * $iHeight & "]", $Scan) ;struct erstellen, um mit AutoIt die Daten zu bekommenFor $i = 1 To $iWidth * ($iHeight - 1) ;jedes pixel
[/autoit] [autoit][/autoit] [autoit]
$pixel = BitXOR(DllStructGetData($struct, 1, $i), 0xFFFFFF) ;lesen und XORen
DllStructSetData($struct, 1, $pixel, $i) ;Pixel schreiben
Next_GDIPlus_BitmapUnlockBits($hBitmap, $hBitmapData)
[/autoit] [autoit][/autoit] [autoit]
_GDIPlus_ImageSaveToFile($hBitmap, "invert.jpg")ShellExecute("invert.jpg")
[/autoit] -
Eigentlich wollte ich eine Lösung mit _WinAPI_BitBlt posten, aber ich häng da schon seit gestern fest.
Mittlerweile hab ich so viel ein und ausgebaut, dass ich garnicht mehr weiß, wie es ursprünglich aussehen sollte.Mag mir vielleicht jemand erklären, was ich falsch gemacht habe?
Spoiler anzeigen
[autoit]#include <GDIPlus.au3>
[/autoit] [autoit][/autoit] [autoit]
#include <WindowsConstants.au3>_GDIPlus_Startup()
[/autoit] [autoit][/autoit] [autoit]$sFile = FileOpenDialog("", "", "Alle (*.*)")
[/autoit] [autoit][/autoit] [autoit]
If @error Then Exit$hBild = _GDIPlus_BitmapCreateFromFile($sFile)
[/autoit] [autoit][/autoit] [autoit]
$hBild_Inverted = BitmapInvert($hBild)_GDIPlus_ImageSaveToFile($hBild_Inverted, StringTrimRight($sFile, 4) & "_inverted.bmp")
[/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]Func BitmapInvert($hBitmap)
[/autoit] [autoit][/autoit] [autoit]
Local $iWidth, $iHeigth, $hBitmap_New, $hBitmap_Old
Local $hDC_Source, $hDC_Dest, $vReturn$iWidth = _GDIPlus_ImageGetWidth($hBitmap)
[/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]
$iHeigth = _GDIPlus_ImageGetHeight($hBitmap)
;~ $hBitmap_New = _GDIPlus_BitmapCloneArea($hBitmap, 0, 0, $iWidth, $iHeigth)$hDC_Source = _WinAPI_CreateCompatibleDC(0)
[/autoit] [autoit][/autoit] [autoit]
$hDC_Dest = _WinAPI_CreateCompatibleDC(0)$hBitmap_New = _WinAPI_CreateCompatibleBitmap($hDC_Dest,$iWidth,$iHeigth)
[/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]
$hBitmap_Old = _GDIPlus_BitmapCreateHBITMAPFromBitmap($hBitmap)$vReturn = _WinAPI_SelectObject($hDC_Dest, $hBitmap_New) ; nur für's debug in Var schreiben
[/autoit] [autoit][/autoit] [autoit]
$vReturn = _WinAPI_SelectObject($hDC_Source, $hBitmap_Old) ; nur für's debug in Var schreiben
$vReturn = _WinAPI_BitBlt($hDC_Dest, 0, 0, $iWidth, $iHeigth, $hDC_Source, 0, 0, $SRCINVERT)ConsoleWrite(_WinAPI_GetLastError() & @CRLF)
[/autoit] [autoit][/autoit] [autoit]$vReturn = _WinAPI_DeleteDC($hDC_Source)
[/autoit] [autoit][/autoit] [autoit]
$vReturn = _WinAPI_DeleteDC($hDC_Dest)Return _GDIPlus_BitmapCreateFromHBITMAP($hBitmap_New)
[/autoit]
EndFunc ;==>BitmapInvert -
Hi Seubo, Deine Idee war klasse!
Allerdings hattest du per XOR deine dest_bitmap verknüpfen wollen. In dieser ist aber, da neu angelegt, jedes Pixel 0x00000000. Um zu invertieren, müsstest du erst das dest_Bitmap mit 0xFFFFFFFF füllen!
Oder du machst es wie der faule Andy, der benutzt beim Blitten den ParameterZitat von Hilfe zu Bitblt$DSTINVERT - Invertiert die Farben des Ziel-Rechtecks (umkehren)
und spart sich so die 2. Bitmap.Spoiler anzeigen
[autoit]#include <GDIPlus.au3>
[/autoit] [autoit][/autoit] [autoit]
#include <WindowsConstants.au3>_GDIPlus_Startup()
[/autoit] [autoit][/autoit] [autoit]$sFile = FileOpenDialog("", "", "Alle (*.*)")
[/autoit] [autoit][/autoit] [autoit]
If @error Then Exit$hBild = _GDIPlus_BitmapCreateFromFile($sFile)
[/autoit] [autoit][/autoit] [autoit]
$hBild_Inverted = BitmapInvert($hBild)FileDelete(StringTrimRight($sFile, 4) & "_inverted.bmp")
[/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]
$s = _GDIPlus_ImageSaveToFile($hBild_Inverted, StringTrimRight($sFile, 4) & "_inverted.bmp")
ShellExecute(StringTrimRight($sFile, 4) & "_inverted.bmp")Func BitmapInvert($hBitmap)
[/autoit] [autoit][/autoit] [autoit]
Local $iWidth, $iHeigth, $hBitmap_New, $hBitmap_Old
Local $hDC_Source, $hDC_Dest, $vReturn$iWidth = _GDIPlus_ImageGetWidth($hBitmap)
[/autoit] [autoit][/autoit] [autoit]
$iHeigth = _GDIPlus_ImageGetHeight($hBitmap)$hDC_Source = _WinAPI_CreateCompatibleDC(0)
[/autoit] [autoit][/autoit] [autoit]
$hBitmap_Old = _GDIPlus_BitmapCreateHBITMAPFromBitmap($hBitmap)$vReturn = _WinAPI_SelectObject($hDC_Source, $hBitmap_Old) ; nur für's debug in Var schreiben
[/autoit] [autoit][/autoit] [autoit][/autoit]
$vReturn = _WinAPI_BitBlt($hDC_Source, 0, 0, $iWidth, $iHeigth, $hDC_Source, 0, 0, $dstinvert)
$vReturn = _WinAPI_DeleteDC($hDC_Source)
Return _GDIPlus_BitmapCreateFromHBITMAP($hBitmap_Old)
EndFunc ;==>BitmapInvert -
Hi Seubo, Deine Idee war klasse!
Allerdings hattest du per XOR deine dest_bitmap verknüpfen wollen. In dieser ist aber, da neu angelegt, jedes Pixel 0x00000000. Um zu invertieren, müsstest du erst das dest_Bitmap mit 0xFFFFFFFF füllen!
Oder du machst es wie der faule Andy, der benutzt beim Blitten den Parameter
und spart sich so die 2. Bitmap.Spoiler anzeigen
[autoit]#include <GDIPlus.au3>
[/autoit] [autoit][/autoit] [autoit]
#include <WindowsConstants.au3>_GDIPlus_Startup()
[/autoit] [autoit][/autoit] [autoit]$sFile = FileOpenDialog("", "", "Alle (*.*)")
[/autoit] [autoit][/autoit] [autoit]
If @error Then Exit$hBild = _GDIPlus_BitmapCreateFromFile($sFile)
[/autoit] [autoit][/autoit] [autoit]
$hBild_Inverted = BitmapInvert($hBild)FileDelete(StringTrimRight($sFile, 4) & "_inverted.bmp")
[/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]
$s = _GDIPlus_ImageSaveToFile($hBild_Inverted, StringTrimRight($sFile, 4) & "_inverted.bmp")
ShellExecute(StringTrimRight($sFile, 4) & "_inverted.bmp")Func BitmapInvert($hBitmap)
[/autoit] [autoit][/autoit] [autoit]
Local $iWidth, $iHeigth, $hBitmap_New, $hBitmap_Old
Local $hDC_Source, $hDC_Dest, $vReturn$iWidth = _GDIPlus_ImageGetWidth($hBitmap)
[/autoit] [autoit][/autoit] [autoit]
$iHeigth = _GDIPlus_ImageGetHeight($hBitmap)$hDC_Source = _WinAPI_CreateCompatibleDC(0)
[/autoit] [autoit][/autoit] [autoit]
$hBitmap_Old = _GDIPlus_BitmapCreateHBITMAPFromBitmap($hBitmap)$vReturn = _WinAPI_SelectObject($hDC_Source, $hBitmap_Old) ; nur für's debug in Var schreiben
[/autoit] [autoit][/autoit] [autoit][/autoit]
$vReturn = _WinAPI_BitBlt($hDC_Source, 0, 0, $iWidth, $iHeigth, $hDC_Source, 0, 0, $dstinvert)
$vReturn = _WinAPI_DeleteDC($hDC_Source)
Return _GDIPlus_BitmapCreateFromHBITMAP($hBitmap_Old)
EndFunc ;==>BitmapInvertEinfach, schnell und effizient!
Gruß,
UEZ -
ich möchte ein Bild auf mein Desktop malen, welches nur schwarz enthält (.png)
Diese ist ein Fadenkreuz und im Anhang
Es sollte dann immer sichtbar seinHier, das hab ich mal auf die Schnelle zusammengeschustert.
Es geht mit Sicherheit auch anders (evtl. auch einfacher), aber ich hatte so ein ähnliches Script schon hier
rumliegen - da ging es darum, wie mit einem Rotstift auf den Bildschirm zu malen.Spoiler anzeigen
[autoit]
[/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]
#include <GDIPlus.au3>
#include <WindowsConstants.au3>;Variablen deklarieren
[/autoit] [autoit][/autoit] [autoit]
Local $hGUI, $hGraphics
Local $aMPos, $aMPos_Old[4]
Local $iCH_Width, $iCH_Height;GDI+ initialisieren öffnen und ESC als HotKey festlegen
[/autoit] [autoit][/autoit] [autoit]
_GDIPlus_Startup()
HotKeySet("{ESC}", "_Exit");Bild (fadenkreuz) laden
[/autoit] [autoit][/autoit] [autoit]
$hCrossHair = _GDIPlus_ImageLoadFromFile(@ScriptDir & "\crosshair.png")
If Not $hCrossHair Then Exit MsgBox(0,"",StringFormat("'%s' konnte nicht geunden werden.",@ScriptDir & "\crosshair.png"))$iCH_Width = _GDIPlus_ImageGetWidth($hCrossHair)
[/autoit] [autoit][/autoit] [autoit]
$iCH_Height = _GDIPlus_ImageGetHeight($hCrossHair);Transparente GUI erstellen
[/autoit] [autoit][/autoit] [autoit]
$hDummy = GUICreate("") ; Dummy GUI, damit richtiges nicht in Taskleiste auftaucht.
$hGUI = GUICreate("", $iCH_Width, $iCH_Height, 0, 0, $WS_POPUP, BitOR($WS_EX_LAYERED, $WS_EX_TOPMOST, $WS_EX_TRANSPARENT), $hDummy)
GUISetBkColor(0xABCDEF, $hGUI)
_WinAPI_SetLayeredWindowAttributes($hGUI, 0xABCDEF, 255);Graphic-Objekt erstellen und GUI anzeigen
[/autoit] [autoit][/autoit] [autoit]
$hGraphics = _GDIPlus_GraphicsCreateFromHWND($hGUI)
GUISetState()_GDIPlus_GraphicsDrawImage($hGraphics,$hCrossHair,0,0)
[/autoit] [autoit][/autoit] [autoit]While Sleep(10)
[/autoit] [autoit][/autoit] [autoit]
$aMPos = MouseGetPos()
If $aMPos[0] <> $aMPos_Old[0] Or $aMPos[1] <> $aMPos_Old[1] Then
WinMove($hGUI, "", $aMPos[0] - $iCH_Width / 2, $aMPos[1] - $iCH_Height / 2)
If ($aMPos[0] + $iCH_Width > @DesktopWidth) Or ($aMPos[1] + $iCH_Height > @DesktopHeight) Or ($aMPos[0] - $iCH_Width < 0) Or ($aMPos[1] - $iCH_Height < 0) Then _GDIPlus_GraphicsDrawImage($hGraphics,$hCrossHair,0,0)
$aMPos_Old = $aMPos
EndIfWEnd
[/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]Func _Exit()
[/autoit]
_GDIPlus_GraphicsDispose($hGraphics)
GUIDelete($hGUI)
Exit
EndFunc ;==>_Exit