Jump to content

Image quality is bad compared to paint


Recommended Posts

#Region ;**** Directives created by AutoIt3Wrapper_GUI ****
#AutoIt3Wrapper_Icon=car.ico
#EndRegion ;**** Directives created by AutoIt3Wrapper_GUI ****
#include <GDIPlus.au3>
#include <File.au3>
#include <Array.au3>
#include <ColorConstants.au3>
#include <GUIConstantsEx.au3>
#include <WindowsConstants.au3>
#include <ProgressConstants.au3>

; Declare array
Dim $Images[1]
; Gets all JPG files in the current directory (@ScriptDir).
Local $search = FileFindFirstFile("*.jpg")

; Check if the search was successful
If $search = -1 Then
    MsgBox(0, "Error", "No JPG files could be found.")
    Exit
EndIf

; Resize array
While 1
    If IsArray($Images) Then
        Local $Bound = UBound($Images)
        ReDim $Images[$Bound+1]
    EndIf
    $Images[$Bound] = FileFindNextFile($search)
    If @error Then ExitLoop
WEnd

; Close the search handle
FileClose($search)

; Create directory "resized" if not there yet
$nymappe = InputBox("Mappe / Bil Navn", "Mappe / Bil Navn")
If NOT FileExists(@ScriptDir & "\" & $nymappe & "\") Then
    DirCreate(@ScriptDir & "\" & $nymappe & "\")
EndIf

; Loop for JPGs - gets dimension of JPG and calls resize function to resize to 50% width and 50% height
For $i = 1 to Ubound($Images)-1
    If $Images[$i] <> "" AND FileExists(@ScriptDir & "\" & $Images[$i]) Then
        Local $ImagePath = @ScriptDir & "\" & $Images[$i]
        _GDIPlus_Startup()
        Local $hImage = _GDIPlus_ImageLoadFromFile($ImagePath)
        Local $ImageWidth = _GDIPlus_ImageGetWidth($hImage)
        Local $ImageHeight = _GDIPlus_ImageGetHeight($hImage)
        _GDIPlus_ImageDispose($hImage)
        _GDIPlus_Shutdown()
        ;MsgBox(0,"DEBUG", $ImageWidth & " x " & $ImageHeight)
        Local $NewImageWidth = ($ImageWidth / 100) * 15
        Local $NewImageHeight = ($ImageHeight / 100) * 15

        ;MsgBox(0,"DEBUG: " & $i,$Images[$i])
        _ImageResize(@ScriptDir & "\" & $Images[$i], @ScriptDir & "\" & $nymappe & "\" & $Images[$i], $NewImageWidth, $NewImageHeight)
    EndIf
Next

; Resize function
Func _ImageResize($sInImage, $sOutImage, $iW, $iH)
    Local $hWnd, $hDC, $hBMP, $hImage1, $hImage2, $hGraphic, $CLSID, $i = 0

    ;OutFile path, to use later on.
    Local $sOP = StringLeft($sOutImage, StringInStr($sOutImage, "\", 0, -1))

    ;OutFile name, to use later on.
    Local $sOF = StringMid($sOutImage, StringInStr($sOutImage, "\", 0, -1) + 1)

    ;OutFile extension , to use for the encoder later on.
    Local $Ext = StringUpper(StringMid($sOutImage, StringInStr($sOutImage, ".", 0, -1) + 1))

    ; Win api to create blank bitmap at the width and height to put your resized image on.
    $hWnd = _WinAPI_GetDesktopWindow()
    $hDC = _WinAPI_GetDC($hWnd)
    $hBMP = _WinAPI_CreateCompatibleBitmap($hDC, $iW, $iH)
    _WinAPI_ReleaseDC($hWnd, $hDC)

    ;Start GDIPlus
    _GDIPlus_Startup()

    ;Get the handle of blank bitmap you created above as an image
    $hImage1 = _GDIPlus_BitmapCreateFromHBITMAP ($hBMP)

    ;Load the image you want to resize.
    $hImage2 = _GDIPlus_ImageLoadFromFile($sInImage)

    ;Get the graphic context of the blank bitmap
    $hGraphic = _GDIPlus_ImageGetGraphicsContext ($hImage1)

    ;Draw the loaded image onto the blank bitmap at the size you want
    _GDIPLus_GraphicsDrawImageRect($hGraphic, $hImage2, 0, 0, $iW, $iH)

    ;Get the encoder of to save the resized image in the format you want.
    $CLSID = _GDIPlus_EncodersGetCLSID($Ext)

    ;Generate a number for out file that doesn't already exist, so you don't overwrite an existing image.
    Do
        $i += 1
    Until (Not FileExists($sOP & $i & "_" & $sOF))

    ;Prefix the number to the begining of the output filename
    $sOutImage = $sOP & $i & "_" & $sOF

    ;Save the new resized image.
    _GDIPlus_ImageSaveToFileEx($hImage1, $sOutImage, $CLSID)

    ;Clean up and shutdown GDIPlus.
    _GDIPlus_ImageDispose($hImage1)
    _GDIPlus_ImageDispose($hImage2)
    _GDIPlus_GraphicsDispose ($hGraphic)
    _WinAPI_DeleteObject($hBMP)
    _GDIPlus_Shutdown()


EndFunc

Quality gets quite bad compared to using Paint / Photoshop when resizing with GDIPlus
Any idea how to make the quality better?
Thanks in advance

Link to comment
Share on other sites

Try the built-in functions

_GDIPlus_ImageResize
_GDIPlus_ImageScale

Further it makes no sense to  call _GDIPlus_Startup() / _GDIPlus_Shutdown() in a loop. Just call _GDIPlus_Startup() once when you start the script and _GDIPlus_Shutdown() when you exit.

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

Link to comment
Share on other sites

22 minutes ago, UEZ said:

Try the built-in functions

_GDIPlus_ImageResize
_GDIPlus_ImageScale

Further it makes no sense to  call _GDIPlus_Startup() / _GDIPlus_Shutdown() in a loop. Just call _GDIPlus_Startup() once when you start the script and _GDIPlus_Shutdown() when you exit.

Thank you I will look in to that.
Could you give me a small example?:sweating:

Link to comment
Share on other sites

Just now, RyukShini said:

Could you give me a small example?:sweating:

What about the examples in the help file?

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

#Region ;**** Directives created by AutoIt3Wrapper_GUI ****
#AutoIt3Wrapper_Icon=car.ico
#EndRegion ;**** Directives created by AutoIt3Wrapper_GUI ****
#include <GDIPlus.au3>
#include <File.au3>
#include <Array.au3>
#include <ColorConstants.au3>
#include <GUIConstantsEx.au3>
#include <WindowsConstants.au3>
#include <ProgressConstants.au3>

; Declare array
Dim $Images[1]
; Gets all JPG files in the current directory (@ScriptDir).
Local $search = FileFindFirstFile("*.jpg")

; Check if the search was successful
If $search = -1 Then
    MsgBox(0, "Error", "No JPG files could be found.")
    Exit
EndIf

;if no exit then startup gdi
_GDIPlus_Startup()

; Resize array
While 1
    If IsArray($Images) Then
        Local $Bound = UBound($Images)
        ReDim $Images[$Bound+1]
    EndIf
    $Images[$Bound] = FileFindNextFile($search)
    If @error Then ExitLoop
WEnd

; Close the search handle
FileClose($search)

; Create directory "resized" if not there yet
$nymappe = InputBox("Mappe / Bil Navn", "Mappe / Bil Navn")
If NOT FileExists(@ScriptDir & "\" & $nymappe & "\") Then
    DirCreate(@ScriptDir & "\" & $nymappe & "\")
EndIf

; Loop for JPGs - gets dimension of JPG and calls resize function to resize to 50% width and 50% height
For $i = 1 to Ubound($Images)-1
    If $Images[$i] <> "" AND FileExists(@ScriptDir & "\" & $Images[$i]) Then
        Local $ImagePath = @ScriptDir & "\" & $Images[$i]
        _GDIPlus_Startup()
        Local $hImage = _GDIPlus_ImageLoadFromFile($ImagePath)
        Local $ImageWidth = _GDIPlus_ImageGetWidth($hImage)
        Local $ImageHeight = _GDIPlus_ImageGetHeight($hImage)
        _GDIPlus_ImageDispose($hImage)
        _GDIPlus_Shutdown()
        ;MsgBox(0,"DEBUG", $ImageWidth & " x " & $ImageHeight)
        Local $NewImageWidth = ($ImageWidth / 100) * 15
        Local $NewImageHeight = ($ImageHeight / 100) * 15

        ;MsgBox(0,"DEBUG: " & $i,$Images[$i])
        _ImageResize(@ScriptDir & "\" & $Images[$i], @ScriptDir & "\" & $nymappe & "\" & $Images[$i], $NewImageWidth, $NewImageHeight)
    EndIf
Next

; Resize function
Func _ImageResize($sInImage, $sOutImage, $iW, $iH)

    ;OutFile path, to use later on.
    Local $sOP = StringLeft($sOutImage, StringInStr($sOutImage, "\", 0, -1))

    ;OutFile name, to use later on.
    Local $sOF = StringMid($sOutImage, StringInStr($sOutImage, "\", 0, -1) + 1)

    ;OutFile extension , to use for the encoder later on.
    Local $Ext = StringUpper(StringMid($sOutImage, StringInStr($sOutImage, ".", 0, -1) + 1))

    ;Load the image you want to resize.
    $hImage = _GDIPlus_ImageLoadFromFile ($sInImage)

    ;Resize
    $hBitmap_Scaled = _GDIPlus_ImageResize($hImage, $iW, $iH)

    ;U can test this too
    ;$hBitmap_Scaled = _GDIPlus_ImageScale($hImage, 0.15, 0.15)

    ;Get the encoder of to save the resized image in the format you want.
    $CLSID = _GDIPlus_EncodersGetCLSID($Ext)

    ;Generate a number for out file that doesn't already exist, so you don't overwrite an existing image.
    Do
        $i += 1
    Until (Not FileExists($sOP & $i & "_" & $sOF))

    ;Prefix the number to the begining of the output filename
    $sOutImage = $sOP & $i & "_" & $sOF

    ;Save the new resized image.
    _GDIPlus_ImageSaveToFileEx($hBitmap_Scaled, $sOutImage, $CLSID)

    ;Clean up and shutdown GDIPlus.
    _GDIPlus_ImageDispose($hImage)
    _GDIPlus_BitmapDispose($hBitmap_Scaled)

EndFunc

_GDIPlus_Shutdown()

 

im not sure if this improve quality.

Link to comment
Share on other sites

58 minutes ago, Synapsee said:
#Region ;**** Directives created by AutoIt3Wrapper_GUI ****
#AutoIt3Wrapper_Icon=car.ico
#EndRegion ;**** Directives created by AutoIt3Wrapper_GUI ****
#include <GDIPlus.au3>
#include <File.au3>
#include <Array.au3>
#include <ColorConstants.au3>
#include <GUIConstantsEx.au3>
#include <WindowsConstants.au3>
#include <ProgressConstants.au3>

; Declare array
Dim $Images[1]
; Gets all JPG files in the current directory (@ScriptDir).
Local $search = FileFindFirstFile("*.jpg")

; Check if the search was successful
If $search = -1 Then
    MsgBox(0, "Error", "No JPG files could be found.")
    Exit
EndIf

;if no exit then startup gdi
_GDIPlus_Startup()

; Resize array
While 1
    If IsArray($Images) Then
        Local $Bound = UBound($Images)
        ReDim $Images[$Bound+1]
    EndIf
    $Images[$Bound] = FileFindNextFile($search)
    If @error Then ExitLoop
WEnd

; Close the search handle
FileClose($search)

; Create directory "resized" if not there yet
$nymappe = InputBox("Mappe / Bil Navn", "Mappe / Bil Navn")
If NOT FileExists(@ScriptDir & "\" & $nymappe & "\") Then
    DirCreate(@ScriptDir & "\" & $nymappe & "\")
EndIf

; Loop for JPGs - gets dimension of JPG and calls resize function to resize to 50% width and 50% height
For $i = 1 to Ubound($Images)-1
    If $Images[$i] <> "" AND FileExists(@ScriptDir & "\" & $Images[$i]) Then
        Local $ImagePath = @ScriptDir & "\" & $Images[$i]
        _GDIPlus_Startup()
        Local $hImage = _GDIPlus_ImageLoadFromFile($ImagePath)
        Local $ImageWidth = _GDIPlus_ImageGetWidth($hImage)
        Local $ImageHeight = _GDIPlus_ImageGetHeight($hImage)
        _GDIPlus_ImageDispose($hImage)
        _GDIPlus_Shutdown()
        ;MsgBox(0,"DEBUG", $ImageWidth & " x " & $ImageHeight)
        Local $NewImageWidth = ($ImageWidth / 100) * 15
        Local $NewImageHeight = ($ImageHeight / 100) * 15

        ;MsgBox(0,"DEBUG: " & $i,$Images[$i])
        _ImageResize(@ScriptDir & "\" & $Images[$i], @ScriptDir & "\" & $nymappe & "\" & $Images[$i], $NewImageWidth, $NewImageHeight)
    EndIf
Next

; Resize function
Func _ImageResize($sInImage, $sOutImage, $iW, $iH)

    ;OutFile path, to use later on.
    Local $sOP = StringLeft($sOutImage, StringInStr($sOutImage, "\", 0, -1))

    ;OutFile name, to use later on.
    Local $sOF = StringMid($sOutImage, StringInStr($sOutImage, "\", 0, -1) + 1)

    ;OutFile extension , to use for the encoder later on.
    Local $Ext = StringUpper(StringMid($sOutImage, StringInStr($sOutImage, ".", 0, -1) + 1))

    ;Load the image you want to resize.
    $hImage = _GDIPlus_ImageLoadFromFile ($sInImage)

    ;Resize
    $hBitmap_Scaled = _GDIPlus_ImageResize($hImage, $iW, $iH)

    ;U can test this too
    ;$hBitmap_Scaled = _GDIPlus_ImageScale($hImage, 0.15, 0.15)

    ;Get the encoder of to save the resized image in the format you want.
    $CLSID = _GDIPlus_EncodersGetCLSID($Ext)

    ;Generate a number for out file that doesn't already exist, so you don't overwrite an existing image.
    Do
        $i += 1
    Until (Not FileExists($sOP & $i & "_" & $sOF))

    ;Prefix the number to the begining of the output filename
    $sOutImage = $sOP & $i & "_" & $sOF

    ;Save the new resized image.
    _GDIPlus_ImageSaveToFileEx($hBitmap_Scaled, $sOutImage, $CLSID)

    ;Clean up and shutdown GDIPlus.
    _GDIPlus_ImageDispose($hImage)
    _GDIPlus_BitmapDispose($hBitmap_Scaled)

EndFunc

_GDIPlus_Shutdown()

 

im not sure if this improve quality.

It did not, thank you a lot for trying, but it didn't make any changes really :/
Both of these:
 

;Resize
    $hBitmap_Scaled = _GDIPlus_ImageResize($hImage, $iW, $iH)

    ;U can test this too
    ;$hBitmap_Scaled = _GDIPlus_ImageScale($hImage, 0.15, 0.15)

 

Edited by RyukShini
Link to comment
Share on other sites

maybe can u post 2 img. the original one and the paint result u target. like this we can see the quality problem and wait a "GDI expert" solution.

I prefer a full AutoIt Version but maybe u can look on a tiers party software (with command line) for improve quality.

Edited by Synapsee
Link to comment
Share on other sites

wow ! i have a solution, we need set the quality jpeg encoder setting, by default seems not be quality=100.

 

...
    ;Get the encoder of to save the resized image in the format you want.
    $CLSID = _GDIPlus_EncodersGetCLSID($Ext)






    ; code found here :
    ; https://www.autoitscript.com/autoit3/docs/libfunctions/_GDIPlus_ImageSaveToStream.htm
    
        Local $sImgCLSID = _GDIPlus_EncodersGetCLSID("jpg") ;create CLSID for a JPG image file type
        Local $tGUID = _WinAPI_GUIDFromString($sImgCLSID) ;convert CLSID GUID to binary form and returns $tagGUID structure
        Local $tParams = _GDIPlus_ParamInit(1) ;initialize an encoder parameter list and return $tagGDIPENCODERPARAMS structure
        Local $tData = DllStructCreate("int Quality") ;create struct to set JPG quality setting
        DllStructSetData($tData, "Quality", 100) ;quality 0-100 (0: lowest, 100: highest)
        Local $pData = DllStructGetPtr($tData) ;get pointer from quality struct
        _GDIPlus_ParamAdd($tParams, $GDIP_EPGQUALITY, 1, $GDIP_EPTLONG, $pData) ;add a value to an encoder parameter list




    ;Generate a number for out file that doesn't already exist, so you don't overwrite an existing image.
    Do
        $i += 1
    Until (Not FileExists($sOP & $i & "_" & $sOF))

    ;Prefix the number to the begining of the output filename
    $sOutImage = $sOP & $i & "_" & $sOF




    ;Save the new resized image.
    _GDIPlus_ImageSaveToFileEx($hBitmap_Scaled, $sOutImage, $CLSID)
    _GDIPlus_ImageSaveToFileEx($hBitmap_Scaled, $sOutImage & "2.jpg", $CLSID, $tParams); <=========== create a 100% quality output
...

 

Link to comment
Share on other sites

1 hour ago, Synapsee said:

wow ! i have a solution, we need set the quality jpeg encoder setting, by default seems not be quality=100.

 

...
    ;Get the encoder of to save the resized image in the format you want.
    $CLSID = _GDIPlus_EncodersGetCLSID($Ext)






    ; code found here :
    ; https://www.autoitscript.com/autoit3/docs/libfunctions/_GDIPlus_ImageSaveToStream.htm
    
        Local $sImgCLSID = _GDIPlus_EncodersGetCLSID("jpg") ;create CLSID for a JPG image file type
        Local $tGUID = _WinAPI_GUIDFromString($sImgCLSID) ;convert CLSID GUID to binary form and returns $tagGUID structure
        Local $tParams = _GDIPlus_ParamInit(1) ;initialize an encoder parameter list and return $tagGDIPENCODERPARAMS structure
        Local $tData = DllStructCreate("int Quality") ;create struct to set JPG quality setting
        DllStructSetData($tData, "Quality", 100) ;quality 0-100 (0: lowest, 100: highest)
        Local $pData = DllStructGetPtr($tData) ;get pointer from quality struct
        _GDIPlus_ParamAdd($tParams, $GDIP_EPGQUALITY, 1, $GDIP_EPTLONG, $pData) ;add a value to an encoder parameter list




    ;Generate a number for out file that doesn't already exist, so you don't overwrite an existing image.
    Do
        $i += 1
    Until (Not FileExists($sOP & $i & "_" & $sOF))

    ;Prefix the number to the begining of the output filename
    $sOutImage = $sOP & $i & "_" & $sOF




    ;Save the new resized image.
    _GDIPlus_ImageSaveToFileEx($hBitmap_Scaled, $sOutImage, $CLSID)
    _GDIPlus_ImageSaveToFileEx($hBitmap_Scaled, $sOutImage & "2.jpg", $CLSID, $tParams); <=========== create a 100% quality output
...

 

Amazing!
Will definitely try this when I get back to work.

Thanks a lot ;)

Link to comment
Share on other sites

2 hours ago, Synapsee said:

can u post the file source jpg for sample ?

I can give you a * 15 with paint and * 15 GDI plus!
Would you like that?

Still not good enough quality!
let me know and i'll sent you 2 pics.

Edited by RyukShini
Link to comment
Share on other sites

3 minutes ago, UEZ said:

Why not saving in PNG format?

Do you expect the quality to be better?
It still doesn't change the fact that Paint makes the quality better than GDIPlus for .jpg images.

But thank you for the suggestion!

Link to comment
Share on other sites

  • 7 months later...
On ‎08‎.‎07‎.‎2016 at 3:36 PM, RyukShini said:

Paint makes the quality better than GDIPlus for .jpg images

Is still actual?

#include <ScreenCapture.au3>

$hBMP = _ScreenCapture_Capture()

; GDI+ resizign
_GDIPlus_Startup()
$hImage = _GDIPlus_BitmapCreateFromHBITMAP($hBMP)
$hScale = _GDIPlus_ImageScale($hImage, 0.5, 0.5)
_GDIPlus_ImageSaveToFile($hScale, "GDIP.jpg")

; gdi32 resizing
$iW = _GDIPlus_ImageGetWidth($hImage)
$iH = _GDIPlus_ImageGetHeight($hImage)
$iW2 = $iW / 2
$iH2 = $iH / 2
$hDC = _WinAPI_GetDC(0)
$hDC1 = _WinAPI_CreateCompatibleDC($hDC)
_WinAPI_SelectObject($hDC1, $hBMP)
$hDC2 = _WinAPI_CreateCompatibleDC($hDC)
$hBMP2 = _WinAPI_CreateCompatibleBitmap($hDC, $iW2, $iH2)
_WinAPI_SelectObject($hDC2, $hBMP2)

_WinAPI_SetStretchBltMode($hDC2, 3) ; looks like Paint resizing
;~ _WinAPI_SetStretchBltMode($hDC2, 4) ; looks better than Paint

_WinAPI_StretchBlt($hDC2, 0, 0, $iW2, $iH2, $hDC1, 0, 0, $iW, $iH, 0x00CC0020) ; $SRCCOPY
$hBitmap = _GDIPlus_BitmapCreateFromHBITMAP($hBMP2)
_GDIPlus_ImageSaveToFile($hBitmap, "Paint.jpg")

; cleaning
_WinAPI_DeleteObject($hBMP)
_WinAPI_DeleteObject($hBMP2)
_WinAPI_ReleaseDC(0, $hDC)
_WinAPI_DeleteDC($hDC1)
_WinAPI_DeleteDC($hDC2)
_GDIPlus_ImageDispose($hScale)
_GDIPlus_ImageDispose($hImage)
_GDIPlus_ImageDispose($hBitmap)
_GDIPlus_Shutdown()

 

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

×
×
  • Create New...