Jump to content

Image quality in resizing GUI


Lights_On
 Share

Recommended Posts

Hi,

I have a GUI that is able to resize.  The GUI contains an Image.  The image is refreshed at set intervals. My issue is image quality. I am using a .gif and the quality of the image displayed is not as good as if I open the image separately.  I read it can be improved using GDI but not sure how to implement this even after some testing as I need resizing capabilities.  I am happy to not use GDI if there are better ways to increase image quality.

Below is a test script that can be used to replicate the issue.

 

#include <GUIConstantsEx.au3>
#include <WindowsConstants.au3>
#include <ScreenCapture.au3>

Local $TESTQuality  =   GUICreate("TESTQuality", 1000, 590, -1, -1, BitOR($WS_SIZEBOX, $WS_MAXIMIZEBOX, $WS_MINIMIZEBOX))
_ScreenCapture_Capture(@DesktopDir & "\atestpic.jpg")
Local $ImagePath    =   @DesktopDir & "\atestpic.jpg"
Local $Image1       =   GUICtrlCreatePic($ImagePath, 10, 30, 990, 580)
GUICtrlSetResizing($Image1, $GUI_DOCKVCENTER)
Local $time         =   TimerInit()
GUISetState(@SW_SHOW)

While 1
    Switch GUIGetMsg()
        Case $GUI_EVENT_CLOSE
        ExitLoop
    EndSwitch

    ; Refresh the image
    If TimerDiff($time) > 500 Then
        GUICtrlSetImage($Image1, $ImagePath)
        Local $time = TimerInit()
    EndIf
WEnd

GUIDelete($TESTQuality)

 

Any help appreciated.

Edited by Lights_On
Link to comment
Share on other sites

Try something like this here;

#include <Constants.au3>
#include <GDIPlus.au3>
#include <GUIConstantsEx.au3>
#include <WindowsConstants.au3>

Global Const $STM_SETIMAGE = 0x0172
Global $sPathKey = "HKLM64\SOFTWARE\AutoIt v3\AutoIt\"
If @OSArch = "x64" Then $sPathKey = "HKLM\SOFTWARE\Wow6432Node\AutoIt v3\AutoIt\"
Global $sImage = RegRead($sPathKey, "InstallDir") & "\Examples\GUI\logo4.gif"

_GDIPlus_Startup()
Global $hBmp = _GDIPlus_BitmapCreateFromFile($sImage)
Global $iW = _GDIPlus_ImageGetWidth($hBmp), $iH = _GDIPlus_ImageGetHeight($hBmp)

Global $hGUI = GUICreate("Test", 235, 112, -1, -1, BitOR($GUI_SS_DEFAULT_GUI, $WS_SIZEBOX, $WS_THICKFRAME), $WS_EX_COMPOSITED)
Global $idPic = GUICtrlCreatePic("", 32, 16, $iW, $iH)
GUICtrlSetResizing(-1, $GUI_DOCKVCENTER + $GUI_DOCKHCENTER)

Global $hHBitmap = _GDIPlus_BitmapCreateHBITMAPFromBitmap($hBmp)
Global $hB = GUICtrlSendMsg($idPic, $STM_SETIMAGE, $IMAGE_BITMAP, $hHBitmap)
If $hB Then _WinAPI_DeleteObject($hB)
GUISetState(@SW_SHOW)

GUIRegisterMsg($WM_SIZE, "WM_SIZE")

While 1
    Switch GUIGetMsg()
        Case $GUI_EVENT_CLOSE
            GUIRegisterMsg($WM_SIZE, "")
            _WinAPI_DeleteObject($hHBitmap)
            _GDIPlus_BitmapDispose($hBmp)
            _GDIPlus_Shutdown()
            GUIDelete()
            Exit
    EndSwitch
WEnd

Func WM_SIZE($hWnd, $Msg, $wParam, $lParam)
    #forceref $Msg, $wParam, $lParam
    Local $aSize = ControlGetPos($hWnd, "", $idPic)
    Local $hBitmap = _GDIPlus_BitmapCreateFromScan0($aSize[2], $aSize[3])
    Local $hContext = _GDIPlus_ImageGetGraphicsContext($hBitmap)
    _GDIPlus_GraphicsSetInterpolationMode($hContext, 5)
    _GDIPlus_GraphicsDrawImageRect($hContext, $hBmp, 0, 0, $aSize[2], $aSize[3])
    _GDIPlus_GraphicsDispose($hContext)
    Local $hHBitmap = _GDIPlus_BitmapCreateHBITMAPFromBitmap($hBitmap)
    Local $hB = GUICtrlSendMsg($idPic, $STM_SETIMAGE, $IMAGE_BITMAP, $hHBitmap)
    If $hB Then _WinAPI_DeleteObject($hB)
    _WinAPI_DeleteObject($hHBitmap)
    _GDIPlus_BitmapDispose($hBitmap)
    Return "GUI_RUNDEFMSG"
EndFunc

 

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!
¯\_(ツ)_/¯  ٩(●̮̮̃•̃)۶ ٩(-̮̮̃-̃)۶ૐ

Link to comment
Share on other sites

Hi UEZ,

Thank you for taking the time to help me.

I have had a play with your code to understand it better and as part of doing this made some changes so it was more familiar to my example.  My code (yours amended) is below:

 

#include <Constants.au3>
#include <GDIPlus.au3>
#include <GUIConstantsEx.au3>
#include <WindowsConstants.au3>
#include <ScreenCapture.au3>


Global Const $STM_SETIMAGE = 0x0172
;Global $sPathKey = "HKLM64\SOFTWARE\AutoIt v3\AutoIt\"
;If @OSArch = "x64" Then $sPathKey = "HKLM\SOFTWARE\Wow6432Node\AutoIt v3\AutoIt\"
;Global $sImage = RegRead($sPathKey, "InstallDir") & "\Examples\GUI\logo4.gif"
_ScreenCapture_Capture(@DesktopDir & "\atestpic.gif")
Global $sImage = @DesktopDir & "\atestpic.gif"

_GDIPlus_Startup()
Global $hBmp = _GDIPlus_BitmapCreateFromFile($sImage)
Global $iW = _GDIPlus_ImageGetWidth($hBmp), $iH = _GDIPlus_ImageGetHeight($hBmp)

;Global $hGUI = GUICreate("Test", 235, 112, -1, -1, BitOR($GUI_SS_DEFAULT_GUI, $WS_SIZEBOX, $WS_THICKFRAME), $WS_EX_COMPOSITED)
Global $hGUI = GUICreate("Test", 1000, 590, -1, -1, BitOR($WS_SIZEBOX, $WS_MAXIMIZEBOX, $WS_MINIMIZEBOX))


;Global $idPic = GUICtrlCreatePic("", 32, 16, $iW, $iH)
Global $idPic = GUICtrlCreatePic("", 10, 30, $iW, $iH)

GUICtrlSetResizing(-1, $GUI_DOCKVCENTER + $GUI_DOCKHCENTER)

Global $hHBitmap = _GDIPlus_BitmapCreateHBITMAPFromBitmap($hBmp)
Global $hB = GUICtrlSendMsg($idPic, $STM_SETIMAGE, $IMAGE_BITMAP, $hHBitmap)
If $hB Then _WinAPI_DeleteObject($hB)
Local $time         =   TimerInit()
GUISetState(@SW_SHOW)

GUIRegisterMsg($WM_SIZE, "WM_SIZE")

While 1
    Switch GUIGetMsg()
        Case $GUI_EVENT_CLOSE
            GUIRegisterMsg($WM_SIZE, "")
            _WinAPI_DeleteObject($hHBitmap)
            _GDIPlus_BitmapDispose($hBmp)
            _GDIPlus_Shutdown()
            GUIDelete()
            Exit

    EndSwitch

    ; Refresh the image
    If TimerDiff($time) > 500 Then
        GUICtrlSetImage($idPic, $sImage)
        Local $time = TimerInit()
    EndIf

WEnd

Func WM_SIZE($hWnd, $Msg, $wParam, $lParam)
    #forceref $Msg, $wParam, $lParam
    Local $aSize = ControlGetPos($hWnd, "", $idPic)
    Local $hBitmap = _GDIPlus_BitmapCreateFromScan0($aSize[2], $aSize[3])
    Local $hContext = _GDIPlus_ImageGetGraphicsContext($hBitmap)
    _GDIPlus_GraphicsSetInterpolationMode($hContext, 5)
    _GDIPlus_GraphicsDrawImageRect($hContext, $hBmp, 0, 0, $aSize[2], $aSize[3])
    _GDIPlus_GraphicsDispose($hContext)
    Local $hHBitmap = _GDIPlus_BitmapCreateHBITMAPFromBitmap($hBitmap)
    Local $hB = GUICtrlSendMsg($idPic, $STM_SETIMAGE, $IMAGE_BITMAP, $hHBitmap)
    If $hB Then _WinAPI_DeleteObject($hB)
    _WinAPI_DeleteObject($hHBitmap)
    _GDIPlus_BitmapDispose($hBitmap)
    Return "GUI_RUNDEFMSG"
EndFunc

Sadly however the quality, if comparing like for like, is in fact worse?  So it would seem, and happy to be wrong, that for my example the GDI option is perhaps not he best way to go?  To test if you run both scripts on the same image, or at least same capture, then it is easy to see the different in picture quality when resizing the window.

Could it just be that the image needs to be a certain format for best res. or am I just not working with images correctly generally?

Thank you again.

Edited by Lights_On
Link to comment
Share on other sites

You have to change the value in line 61 -> _GDIPlus_GraphicsSetInterpolationMode(), e.g. to 

_GDIPlus_GraphicsSetInterpolationMode($hGraphics, $GDIP_INTERPOLATIONMODE_BILINEAR)

But this will slow down the resizing!

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!
¯\_(ツ)_/¯  ٩(●̮̮̃•̃)۶ ٩(-̮̮̃-̃)۶ૐ

Link to comment
Share on other sites

Thank you.  Yes this has helped and it now is an improvement - it is still a little "granular" on colours but is better and now usable. 

I am now seeking to simply things so as to get the bare bones of what i need.  

I got rid of:

;Global $hBmp = _GDIPlus_BitmapCreateFromFile($sImage)
;Global $iW = _GDIPlus_ImageGetWidth($hBmp), $iH = _GDIPlus_ImageGetHeight($hBmp)

and set size manual - this seemed to make no difference and on reading the help file i think i can do my way as below

;Global $idPic = GUICtrlCreatePic("", 32, 16, $iW, $iH)
Global $idPic = GUICtrlCreatePic("", 10, 30, 990, 580)

Please let me know if I am wrong and must not do this.

Link to comment
Share on other sites

  • 1 month later...

Hi,

Sorry for the delay - I have only just been able to come back to this.

I am sadly still struggling.  The below is the latest code I have and if you resize the window from how it opens, to small, to full screen again the quality of the image just degrades and degrades:

#include <Constants.au3>
#include <GDIPlus.au3>
#include <GUIConstantsEx.au3>
#include <WindowsConstants.au3>
#include <ScreenCapture.au3>


Global Const $STM_SETIMAGE = 0x0172
_ScreenCapture_Capture(@DesktopDir & "\atestpic.jpg")
Global $sImage = @DesktopDir & "\atestpic.jpg"

_GDIPlus_Startup()
Global $hBmp = _GDIPlus_BitmapCreateFromFile($sImage)
Global $hGUI = GUICreate("Test", 1000, 590, -1, -1, BitOR($WS_SIZEBOX, $WS_MAXIMIZEBOX, $WS_MINIMIZEBOX))
Global $idPic = GUICtrlCreatePic("", 10, 30, 990, 580)

GUICtrlSetResizing(-1, $GUI_DOCKVCENTER + $GUI_DOCKHCENTER)

Global $hHBitmap = _GDIPlus_BitmapCreateHBITMAPFromBitmap($hBmp)
Global $hB = GUICtrlSendMsg($idPic, $STM_SETIMAGE, $IMAGE_BITMAP, $hHBitmap)
If $hB Then _WinAPI_DeleteObject($hB)


Local $time         =   TimerInit()
GUISetState(@SW_SHOW)

GUIRegisterMsg($WM_SIZE, "WM_SIZE")

While 1
    Switch GUIGetMsg()
        Case $GUI_EVENT_CLOSE
            GUIRegisterMsg($WM_SIZE, "")
            _WinAPI_DeleteObject($hHBitmap)
            _GDIPlus_BitmapDispose($hBmp)
            _GDIPlus_Shutdown()
            GUIDelete()
            Exit

    EndSwitch

    ; Refresh the image
    If TimerDiff($time) > 500 Then
        GUICtrlSetImage($idPic, $sImage)
        Local $time = TimerInit()
    EndIf

WEnd

Func WM_SIZE($hWnd, $Msg, $wParam, $lParam)
    #forceref $Msg, $wParam, $lParam
    Local $aSize = ControlGetPos($hWnd, "", $idPic)
    Local $hBitmap = _GDIPlus_BitmapCreateFromScan0($aSize[2], $aSize[3])
    Local $hContext = _GDIPlus_ImageGetGraphicsContext($hBitmap)
    ;_GDIPlus_GraphicsSetInterpolationMode($hContext, 5)
    _GDIPlus_GraphicsSetInterpolationMode($hContext, 2)
    _GDIPlus_GraphicsDrawImageRect($hContext, $hBmp, 0, 0, $aSize[2], $aSize[3])
    _GDIPlus_GraphicsDispose($hContext)
    Local $hHBitmap = _GDIPlus_BitmapCreateHBITMAPFromBitmap($hBitmap)
    Local $hB = GUICtrlSendMsg($idPic, $STM_SETIMAGE, $IMAGE_BITMAP, $hHBitmap)
    If $hB Then _WinAPI_DeleteObject($hB)
    _WinAPI_DeleteObject($hHBitmap)
    _GDIPlus_BitmapDispose($hBitmap)
    Return "GUI_RUNDEFMSG"
EndFunc

This all seems a lot of code just to refresh an image ensuring the image is the best quality it can be.

Is there not a simpler way? or way to really get great quality of an image in a GUI?

Thank you in advance.

Link to comment
Share on other sites

Hi all,

Further hours spent and this is my latest code (not much change):

#include <Constants.au3>
#include <GDIPlus.au3>
#include <GUIConstantsEx.au3>
#include <WindowsConstants.au3>
#include <ScreenCapture.au3>


; Create the GUI
Global $hGUI = GUICreate("Test", 1000, 590, -1, -1, BitOR($WS_SIZEBOX, $WS_MAXIMIZEBOX, $WS_MINIMIZEBOX))
Global $idPic = GUICtrlCreatePic("", 10, 30, 320, 220)
GUICtrlSetResizing($idPic, $GUI_DOCKVCENTER)

; Sart GDI+
_GDIPlus_Startup()


Global Const $STM_SETIMAGE = 0x0172
_ScreenCapture_Capture(@DesktopDir & "\atestpic.jpg")
Global $sImage = @DesktopDir & "\atestpic.jpg"
Global $hBmp = _GDIPlus_BitmapCreateFromFile($sImage)
Global $hHBitmap = _GDIPlus_BitmapCreateHBITMAPFromBitmap($hBmp)
Global $hB = GUICtrlSendMsg($idPic, $STM_SETIMAGE, $IMAGE_BITMAP, $hHBitmap)

; The bit that ensures corect size?
GUIRegisterMsg($WM_SIZE, "WM_SIZE")

Local $time         =   TimerInit()
GUISetState(@SW_SHOW)

While 1
    Switch GUIGetMsg()
        Case $GUI_EVENT_CLOSE
            GUIRegisterMsg($WM_SIZE, "")
            _WinAPI_DeleteObject($hHBitmap)
            _GDIPlus_BitmapDispose($hBmp)
            _GDIPlus_Shutdown()
            GUIDelete()
            Exit

    EndSwitch

    ; Refresh the image
    If TimerDiff($time) > 5000 Then
        _GDIPlus_BitmapDispose($hBmp)

        _ScreenCapture_Capture(@DesktopDir & "\atestpic.jpg")
        Global $sImage = @DesktopDir & "\atestpic.jpg"
        Global $hBmp = _GDIPlus_BitmapCreateFromFile($sImage)
        Global $hHBitmap = _GDIPlus_BitmapCreateHBITMAPFromBitmap($hBmp)
        Global $hB = GUICtrlSendMsg($idPic, $STM_SETIMAGE, $IMAGE_BITMAP, $hHBitmap)
        If $hB Then _WinAPI_DeleteObject($hB)

        ; The bit that ensures corect size?
        GUIRegisterMsg($WM_SIZE, "WM_SIZE")



        Local $time = TimerInit()
    EndIf

WEnd

Func WM_SIZE($hWnd, $Msg, $wParam, $lParam)
    #forceref $Msg, $wParam, $lParam
    Local $aSize = ControlGetPos($hWnd, "", $idPic)
    Local $hBitmap = _GDIPlus_BitmapCreateFromScan0($aSize[2], $aSize[3])
    Local $hContext = _GDIPlus_ImageGetGraphicsContext($hBitmap)
    ;_GDIPlus_GraphicsSetInterpolationMode($hContext, 5)
    _GDIPlus_GraphicsSetInterpolationMode($hContext, 2)
    _GDIPlus_GraphicsDrawImageRect($hContext, $hBmp, 0, 0, $aSize[2], $aSize[3])
    _GDIPlus_GraphicsDispose($hContext)
    Local $hHBitmap = _GDIPlus_BitmapCreateHBITMAPFromBitmap($hBitmap)
    Local $hB = GUICtrlSendMsg($idPic, $STM_SETIMAGE, $IMAGE_BITMAP, $hHBitmap)
    If $hB Then _WinAPI_DeleteObject($hB)
    _WinAPI_DeleteObject($hHBitmap)
    _GDIPlus_BitmapDispose($hBitmap)
    Return "GUI_RUNDEFMSG"
EndFunc

The issues i'm facing are:

  • The image size does not get set to what it is set to in the scrip at the top (10, 30, 320, 220)? Instead it fills the GUI.
  • The image should refresh every 5 seconds with a new image - but it does not,  I thought disposing of the prior image would work but it has not?
  • When the image refreshes every 5 seconds it does not remain the same size? the image is enlarged and a smaller area of the whole image is seen.

🤯.

...really trying here but seem to be going in circles

Link to comment
Share on other sites

Small progress in putting:

GUIRegisterMsg($WM_SIZE, "WM_SIZE")

underneath:

GUISetState(@SW_SHOW)

Before I had moved it above.  Now this is done i get the correct size image on first run and also when resizing, it is now just the refreshing of the image that is not working, in that it keeps the same image and also changes size.

Edit:  Image is changing, it is just not the correct size.

Edited by Lights_On
Link to comment
Share on other sites

I think i managed it, it seems to now do what i need:

#include <Constants.au3>
#include <GDIPlus.au3>
#include <GUIConstantsEx.au3>
#include <WindowsConstants.au3>
#include <ScreenCapture.au3>

; Create the GUI
Global $hGUI = GUICreate("Test", 1000, 590, -1, -1, BitOR($WS_SIZEBOX, $WS_MAXIMIZEBOX, $WS_MINIMIZEBOX))
Global $idPic = GUICtrlCreatePic("", 10, 30, 320, 220)
GUICtrlSetResizing($idPic, $GUI_DOCKVCENTER)

; Sart GDI+
_GDIPlus_Startup()

Global Const $STM_SETIMAGE = 0x0172
_ScreenCapture_Capture(@DesktopDir & "\atestpic.jpg")
Global $sImage = @DesktopDir & "\atestpic.jpg"
Global $hBmp = _GDIPlus_BitmapCreateFromFile($sImage)
Global $hHBitmap = _GDIPlus_BitmapCreateHBITMAPFromBitmap($hBmp)
Global $hB = GUICtrlSendMsg($idPic, $STM_SETIMAGE, $IMAGE_BITMAP, $hHBitmap)

Local $time         =   TimerInit()
GUISetState(@SW_SHOW)

ReSize()

While 1
    Switch GUIGetMsg()
        Case $GUI_EVENT_CLOSE
            GUIRegisterMsg($WM_SIZE, "")
            _WinAPI_DeleteObject($hHBitmap)
            _GDIPlus_BitmapDispose($hBmp)
            _GDIPlus_Shutdown()
            GUIDelete()
            Exit

        Case $GUI_EVENT_RESIZED, $GUI_EVENT_MAXIMIZE, $GUI_EVENT_RESTORE
            ReSize()
    EndSwitch

    ; Refresh the image
    If TimerDiff($time) > 5000 Then
        _GDIPlus_BitmapDispose($hBmp)
        _ScreenCapture_Capture(@DesktopDir & "\atestpic.jpg")
        Global $sImage = @DesktopDir & "\atestpic.jpg"
        Global $hBmp = _GDIPlus_BitmapCreateFromFile($sImage)
        ReSize()
        Local $time = TimerInit()
    EndIf
WEnd

Func ReSize()

    Local $aSize = ControlGetPos($hGUI, "", $idPic)
    Local $hBitmap = _GDIPlus_BitmapCreateFromScan0($aSize[2], $aSize[3])
    Local $hContext = _GDIPlus_ImageGetGraphicsContext($hBitmap)
    ;_GDIPlus_GraphicsSetInterpolationMode($hContext, 5)
    _GDIPlus_GraphicsSetInterpolationMode($hContext, 2)
    _GDIPlus_GraphicsDrawImageRect($hContext, $hBmp, 0, 0, $aSize[2], $aSize[3])
    _GDIPlus_GraphicsDispose($hContext)
    Local $hHBitmap = _GDIPlus_BitmapCreateHBITMAPFromBitmap($hBitmap)
    Local $hB = GUICtrlSendMsg($idPic, $STM_SETIMAGE, $IMAGE_BITMAP, $hHBitmap)
    If $hB Then _WinAPI_DeleteObject($hB)
    _WinAPI_DeleteObject($hHBitmap)
    _GDIPlus_BitmapDispose($hBitmap)
EndFunc

Is this as it should be?

Improvements?

Link to comment
Share on other sites

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 account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...