Zedna Posted December 30, 2010 Posted December 30, 2010 (edited) I have GUI with picture control where I do some GDI drawing. Now I need to save its content as BMP or PNG image to disk. I think the best will be using _GDIPlus_ImageSaveToFile() for this but there is problem how to obtain hImage from my hDC. I need the idea, maybe I'm doing this completely wrong or there is another easy way for saving GDI drawing from hDC to file. Here is code with some my attempts commented: Result is black image in PNG. expandcollapse popup#include <GUIConstants.au3> #include <WinAPI.au3> #include <GDIPlus.au3> Global $gdi_dll = DllOpen("gdi32.dll") $gui = GUICreate("GDI+",400,300) $pic = GUICtrlCreatePic("",0,0,400,300) ;~ $pic = GUICtrlCreateLabel("",0,0,400,300) $pic_hWnd = ControlGetHandle($gui,"",$pic) $pic_hdc = _WinAPI_GetDC($pic_hWnd) GUIRegisterMsg($WM_PAINT, "MY_WM_PAINT") GUISetState(@SW_SHOW) _GDIPlus_Startup () $hGraphic = _GDIPlus_GraphicsCreateFromHDC ($pic_hdc) ;~ $hGraphic = _GDIPlus_GraphicsCreateFromHWND ($pic_hWnd) ; some GDI+ painting - just test _GDIPlus_GraphicsDrawString ($hGraphic, "Hello world", 150, 150) $hPen = _GDIPlus_PenCreate (0xFFFF0000,2,2) _GDIPlus_GraphicsDrawRect ($hGraphic, 200, 200, 50, 50, $hPen) ;~ $hGraphic = _GDIPlus_ImageGetGraphicsContext ($hImage) ; I need opposite of this ;~ $hImage = _GDIPlus_BitmapCreateFromHBITMAP($hBmp[, $hPal = 0]) $hImage = _GDIPlus_BitmapCreateFromGraphics(400, 300, $hGraphic) ; not sure here ... _GDIPlus_ImageSaveToFile ($hImage, @ScriptDir & "\GDIPlus_Image.png") _GDIPlus_PenDispose ($hPen) _GDIPlus_GraphicsDispose ($hGraphic) _GDIPlus_ImageDispose ($hImage) _GDIPlus_ShutDown () While 1 $msg = GUIGetMsg() If $msg = $GUI_EVENT_CLOSE Then ExitLoop WEnd _WinAPI_ReleaseDC($pic_hWnd, $pic_hdc) Func DrawRedCross($bez_snimku = 0) ; GDI drawing $x = 100 $y = 100 $pen = DLLCall($gdi_dll,"int","CreatePen","int",0,"int",1,"int",0xFF) $obj_orig = DLLCall($gdi_dll,"int","SelectObject","int",$pic_hdc,"int",$pen[0]) DLLCall($gdi_dll,"int","MoveToEx","int",$pic_hdc,"int",$x,"int",$y-10,"int",0) DLLCall($gdi_dll,"int","LineTo","int",$pic_hdc,"int",$x,"int",$y+11) ;vertical line DLLCall($gdi_dll,"int","MoveToEx","int",$pic_hdc,"int",$x-10,"int",$y,"int",0) DLLCall($gdi_dll,"int","LineTo","int",$pic_hdc,"int",$x+11,"int",$y) ;horizontal line DLLCall($gdi_dll,"int","SelectObject","int",$pic_hdc,"int",$obj_orig[0]) DLLCall($gdi_dll,"int","DeleteObject","int",$pen[0]) EndFunc Func MY_WM_PAINT($hWnd, $Msg, $wParam, $lParam) _WinAPI_RedrawWindow($pic_hWnd, 0, 0, $RDW_UPDATENOW) ; force redraw of pic (Rect=0 Region=0) DrawRedCross() ; then draw my stuff on top _WinAPI_RedrawWindow($pic_hWnd, 0, 0, $RDW_VALIDATE) ; then force no-redraw of pic Return $GUI_RUNDEFMSG EndFunc Edited December 30, 2010 by Zedna Resources UDF ResourcesEx UDF AutoIt Forum Search
UEZ Posted December 30, 2010 Posted December 30, 2010 (edited) Here one possibility: expandcollapse popup#include <GUIConstants.au3> #include <WinAPI.au3> #include <GDIPlus.au3> #include <WindowsConstants.au3> Global $gdi_dll = DllOpen("gdi32.dll") $gui = GUICreate("GDI+",400,300) $pic = GUICtrlCreatePic("",0,0,400,300) ;~ $pic = GUICtrlCreateLabel("",0,0,400,300) $pic_hWnd = ControlGetHandle($gui,"",$pic) $pic_hdc = _WinAPI_GetDC($pic_hWnd) GUIRegisterMsg($WM_PAINT, "MY_WM_PAINT") GUISetState(@SW_SHOW) _GDIPlus_Startup () $hGraphic = _GDIPlus_GraphicsCreateFromHDC ($pic_hdc) ;~ $hGraphic = _GDIPlus_GraphicsCreateFromHWND ($pic_hWnd) ; some GDI+ painting - just test _GDIPlus_GraphicsDrawString ($hGraphic, "Hello world", 150, 150) $hPen = _GDIPlus_PenCreate (0xFFFF0000,2,2) _GDIPlus_GraphicsDrawRect ($hGraphic, 200, 200, 50, 50, $hPen) ;~ $hGraphic = _GDIPlus_ImageGetGraphicsContext ($hImage) ; I need opposite of this ;~ $hImage = _GDIPlus_BitmapCreateFromHBITMAP($hBmp[, $hPal = 0]) ;~ $hImage = _GDIPlus_BitmapCreateFromGraphics(400, 300, $hGraphic) ; not sure here ... ;~ _GDIPlus_ImageSaveToFile ($hImage, @ScriptDir & "\GDIPlus_Image.png") _GDIPlus_Save_to_Image(@ScriptDir & "\GDIPlus_Image.png", $gui) _GDIPlus_PenDispose ($hPen) _GDIPlus_GraphicsDispose ($hGraphic) ;~ _GDIPlus_ImageDispose ($hImage) _GDIPlus_ShutDown () While 1 $msg = GUIGetMsg() If $msg = $GUI_EVENT_CLOSE Then ExitLoop WEnd _WinAPI_ReleaseDC($pic_hWnd, $pic_hdc) Func DrawRedCross($bez_snimku = 0) ; GDI drawing $x = 100 $y = 100 $pen = DLLCall($gdi_dll,"int","CreatePen","int",0,"int",1,"int",0xFF) $obj_orig = DLLCall($gdi_dll,"int","SelectObject","int",$pic_hdc,"int",$pen[0]) DLLCall($gdi_dll,"int","MoveToEx","int",$pic_hdc,"int",$x,"int",$y-10,"int",0) DLLCall($gdi_dll,"int","LineTo","int",$pic_hdc,"int",$x,"int",$y+11) ;vertical line DLLCall($gdi_dll,"int","MoveToEx","int",$pic_hdc,"int",$x-10,"int",$y,"int",0) DLLCall($gdi_dll,"int","LineTo","int",$pic_hdc,"int",$x+11,"int",$y) ;horizontal line DLLCall($gdi_dll,"int","SelectObject","int",$pic_hdc,"int",$obj_orig[0]) DLLCall($gdi_dll,"int","DeleteObject","int",$pen[0]) EndFunc Func MY_WM_PAINT($hWnd, $Msg, $wParam, $lParam) _WinAPI_RedrawWindow($pic_hWnd, 0, 0, $RDW_UPDATENOW) ; force redraw of pic (Rect=0 Region=0) DrawRedCross() ; then draw my stuff on top _WinAPI_RedrawWindow($pic_hWnd, 0, 0, $RDW_VALIDATE) ; then force no-redraw of pic Return $GUI_RUNDEFMSG EndFunc ; #FUNCTION# ============================================================================= ; Name.............: _GDIPlus_Save_to_Image ; Description ...: INTERNAL FUNCTION - save drawnelements in GUI to file ; Syntax...........: _GDIPlus_Save_to_Image($file, $hWnd) ; Parameters ...: $file - filename ; $hWnd - handle to GUI ; Author .........: ptrex, ProgAndy, UEZ ; ========================================================================================= Func _GDIPlus_Save_to_Image($file, $hWnd) Local $hDC, $memBmp, $memDC, $hImage, $w, $h, $size, $err, $sCLSID, $ext, $fExt If $file <> "" Or $hWnd <> "" Then $size = WinGetClientSize($hWnd) $w = $size[0] $h = $size[1] $hDC = _WinAPI_GetDC($hWnd) $memDC = _WinAPI_CreateCompatibleDC($hDC) $memBmp = _WinAPI_CreateCompatibleBitmap($hDC, $w, $h) _WinAPI_SelectObject ($memDC, $memBmp) _WinAPI_BitBlt($memDC, 0, 0, $w, $h, $hDC, 0, 0, 0x00CC0020) ; 0x00CC0020 = $SRCCOPY $hImage = _GDIPlus_BitmapCreateFromHBITMAP ($memBmp) $ext = "png,bmp,jpg,tif,gif" $fExt = StringRight($file, 3) If Not StringInStr($ext, $fExt) Then $CLSID = "PNG" $file &= ".png" Else $CLSID = $fExt EndIf $sCLSID = _GDIPlus_EncodersGetCLSID ($CLSID) If Not _GDIPlus_ImageSaveToFileEx ($hImage, $file, $sCLSID) Then $err = 1 _GDIPlus_ImageDispose ($hImage) _WinAPI_ReleaseDC($hWnd, $hDC) _WinAPI_DeleteDC($memDC) _WinAPI_DeleteObject ($memBmp) If $err Then Return SetError(2, 0, 0) Return SetError(0, 0, 0) Else Return SetError(1, 0, 0) EndIf EndFunc Br, UEZ Edited December 30, 2010 by UEZ Please don't send me any personal message and ask for support! I will not reply! Selection of finest graphical examples at Codepen.io The own fart smells best! ✌Her 'sikim hıyar' diyene bir avuç tuz alıp koşma!¯\_(ツ)_/¯ ٩(●̮̮̃•̃)۶ ٩(-̮̮̃-̃)۶ૐ
Zedna Posted December 30, 2010 Author Posted December 30, 2010 (edited) Thank you very much UEZ!!Work like a charm and I'm happy I can do saving of GDI drawing to file now.I very appreciate your help.It's working solution but I think principially it's not optimal because it creates new bitmap and does copy of original bitmap.I'm just curious if there is another more effective way - probably somehow get hBitmap from original DC/hWnd.EDIT2: In code is$hImage = _GDIPlus_BitmapCreateFromHBITMAP ($memBmp)EDIT: In my real project this bitmap (drawing control) is very largeso that's why I'm scared about efficiency Edited December 30, 2010 by Zedna Resources UDF ResourcesEx UDF AutoIt Forum Search
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