Jump to content

Use GDI+ with Screencaptue to save image at specific filesize


 Share

Recommended Posts

I need to take a screenshot and degrade the quality until it reaches 250kb. I had it take a screenshot, read the size, degrade quality and take another until the size was small enough, but that would cause it to take many screenshots and in many cases would delay for too long after you hit Print Screen.

I need to take the file and change the quality of the JPG. The only option I see is _ScreenCapture_SetJPGQuality

But I need to change the quality of an existing image - Not one as it is taken by screencapture. Unless you can degrade while it is in clipboard.

Edited by Rad
Link to comment
Share on other sites

#include <ScreenCapture.au3>
_GDIPlus_Startup()

Global $sFile = @ScriptDir & '\screen.jpg'
Global $iQuality = 100

$hBitmap = _ScreenCapture_Capture('', 0, 0, -1, -1, False)

Do
__ScreenCapture_SaveImage($sFile, $hBitmap, False, $iQuality)
$iQuality -= 10
Until FileGetSize($sFile) <= 1024*250

_GDIPlus_Shutdown()


Func __ScreenCapture_SaveImage($sFileName, $hBitmap, $fFreeBmp, $iQuality)
    Local $hClone, $sCLSID, $tData, $sExt, $hImage, $pParams, $tParams, $iResult, $iX, $iY

    If @error Then Return SetError(-1, -1, False)

    $sExt = StringUpper(_GDIPlus_ExtractFileExt($sFileName))
    $sCLSID = _GDIPlus_EncodersGetCLSID($sExt)
    If $sCLSID = "" Then Return SetError(-2, -2, False)
    $hImage = _GDIPlus_BitmapCreateFromHBITMAP($hBitmap)
    If @error Then Return SetError(-3, -3, False)

    Switch $sExt
        Case "BMP"
            $iX = _GDIPlus_ImageGetWidth($hImage)
            $iY = _GDIPlus_ImageGetHeight($hImage)
            $hClone = _GDIPlus_BitmapCloneArea($hImage, 0, 0, $iX, $iY, $giBMPFormat)
            _GDIPlus_ImageDispose($hImage)
            $hImage = $hClone
        Case "JPG", "JPEG"
            $tParams = _GDIPlus_ParamInit(1)
            $tData = DllStructCreate("int Quality")
            DllStructSetData($tData, "Quality", $iQuality)
            _GDIPlus_ParamAdd($tParams, $GDIP_EPGQUALITY, 1, $GDIP_EPTLONG, DllStructGetPtr($tData))
        Case "TIF", "TIFF"
            $tParams = _GDIPlus_ParamInit(2)
            $tData = DllStructCreate("int ColorDepth;int Compression")
            DllStructSetData($tData, "ColorDepth", $giTIFColorDepth)
            DllStructSetData($tData, "Compression", $giTIFCompression)
            _GDIPlus_ParamAdd($tParams, $GDIP_EPGCOLORDEPTH, 1, $GDIP_EPTLONG, DllStructGetPtr($tData, "ColorDepth"))
            _GDIPlus_ParamAdd($tParams, $GDIP_EPGCOMPRESSION, 1, $GDIP_EPTLONG, DllStructGetPtr($tData, "Compression"))
    EndSwitch
    If IsDllStruct($tParams) Then $pParams = DllStructGetPtr($tParams)

    $iResult = _GDIPlus_ImageSaveToFileEx($hImage, $sFileName, $sCLSID, $pParams)
    _GDIPlus_ImageDispose($hImage)
    If $fFreeBmp Then _WinAPI_DeleteObject($hBitmap)

    Return SetError($iResult = False, 0, $iResult = True)
EndFunc   ;==>_ScreenCapture_SaveImage

Link to comment
Share on other sites

Hi, thanks for the script - Your example works.

I tried integrating it into my own script, however the quality does not degrade. I'm not sure what I'm missing. Here is the main piece of code from my script. It does not give any errors, the image just does not get degraded. It's probably something simple, I'll post this while I try some more things.

$longtitle = $shorttitle&@YEAR&@MON&@MDAY&"-"&@HOUR&@MIN&@SEC&".jpg"    
    $gdiname = @ScriptDir & "\"& $longtitle

    if $AltDown Then 
        $hBmp = _ScreenCapture_CaptureWnd($gdiname, $wnd)
    Else
        $hBmp = _ScreenCapture_Capture($gdiname, 0, 0, -1, -1, false)
    EndIf
    
    $iQuality = 100
    Do
        __ScreenCapture_SaveImage($gdiname, $hBmp, False, $iQuality)
        $iQuality -= 5
    Until FileGetSize($gdiname) <= 1024*250
Link to comment
Share on other sites

Read the function description carefully specially the parameters description because you're not calling it (logically) correctly. The first parameter of either function is the file name to save the image to.

Edit: Sorry, was reading fast without noting. Don't specify a file name string because it'll save the image instead of returning a bitmap object.

Edited by Authenticity
Link to comment
Share on other sites

#Include <GDIPlus.au3>
_GDIPlus_Startup()
$sExt = StringUpper(_GDIPlus_ExtractFileExt($sFileName))
$sCLSID = _GDIPlus_EncodersGetCLSID($sExt)
If $sCLSID = "" Then Return SetError(-2, -2, False)

;load image resource
$hImage = _GDIPlus_ImageLoadFromFile($sFileName)

;set quality, $giJPGQuality is your quality
$tParams = _GDIPlus_ParamInit(1)
$tData = DllStructCreate("int Quality")
DllStructSetData($tData, "Quality", $giJPGQuality)
_GDIPlus_ParamAdd($tParams, $GDIP_EPGQUALITY, 1, $GDIP_EPTLONG, DllStructGetPtr($tData))

;save modification
_GDIPlus_ImageSaveToFileEx($hImage, $sFileName, $sCLSID, $pParams)

;free ressource
_GDIPlus_ImageDispose($hImage)
_GDIPlus_Shutdown()

Edited by trung0407
Link to comment
Share on other sites

Thanks for the help, making the filename into a blank string made everything work just fine. I didn't need to use the second script you provided.

So all I changed was: $hBmp = _ScreenCapture_CaptureWnd('', $wnd)

Thanks again.

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...