Jump to content

Problem when manipulating images with different DPI using GDIPlus


Recommended Posts

I made this little piece of code to crop images into circle shape using GDIPlus. When I try it with 96 DPI images, it works great.

However, when the images are in 300 DPI, the results are incorrect (as you can see in the test image files >>> here). Here is the full script:

#include <GDIplus.au3>

clipCircle("96dpi.jpg", "96dpi_out.jpg")
clipCircle("300dpi.jpg", "300dpi_out.jpg")

Func clipCircle($sImageSource, $sImageDest)
    _GDIPlus_Startup()

    $hBitmapSource = _GDIPlus_BitmapCreateFromFile(@ScriptDir & "\" & $sImageSource)
    $hGraphicsSource = _GDIPlus_ImageGetGraphicsContext($hBitmapSource)
    _GDIPlus_GraphicsSetSmoothingMode($hGraphicsSource, $GDIP_SMOOTHINGMODE_HIGHQUALITY)

    $iX = _GDIPlus_ImageGetWidth($hBitmapSource)
    $iY = _GDIPlus_ImageGetHeight($hBitmapSource)

;~  Create an empty bitmap
;~  This does not work with 300 DPI images
    $hBitmapDest = _GDIPlus_BitmapCreateFromScan0($iX, $iY)
    $hGraphicsDest = _GDIPlus_ImageGetGraphicsContext($hBitmapDest)
    _GDIPlus_GraphicsSetSmoothingMode($hGraphicsDest, $GDIP_SMOOTHINGMODE_HIGHQUALITY)
    _GDIPlus_GraphicsClear($hGraphicsDest, 0xFFFFFFFF)

    $hPath = _GDIPlus_PathCreate()
    _GDIPlus_PathAddEllipse($hPath, 0, 0, $iX, $iY)

    _GDIPlus_GraphicsSetClipPath($hGraphicsDest, $hPath, 0)
    _GDIPlus_GraphicsDrawImage($hGraphicsDest, $hBitmapSource, 0, 0)
    _GDIPlus_ImageSaveToFile($hBitmapDest, @ScriptDir & "\" & $sImageDest)

    _GDIPlus_GraphicsDispose($hGraphicsSource)
    _GDIPlus_BitmapDispose($hBitmapSource)
    _GDIPlus_GraphicsDispose($hGraphicsDest)
    _GDIPlus_BitmapDispose($hBitmapDest)
    _GDIPlus_Shutdown()
EndFunc

Func clipCircle2($sImageSource, $sImageDest)
    _GDIPlus_Startup()

    $hBitmapSource = _GDIPlus_BitmapCreateFromFile(@ScriptDir & "\" & $sImageSource)

    $iX = _GDIPlus_ImageGetWidth($hBitmapSource)
    $iY = _GDIPlus_ImageGetHeight($hBitmapSource)

;~  Clone the source bitmap
;~  This works regardless of the image's DPI
    $hBitmapDest = _GDIPlus_BitmapCloneArea($hBitmapSource, 0, 0, $iX, $iY)
    $hGraphicsDest = _GDIPlus_ImageGetGraphicsContext($hBitmapDest)
    _GDIPlus_GraphicsSetSmoothingMode($hGraphicsDest, $GDIP_SMOOTHINGMODE_HIGHQUALITY)
    _GDIPlus_GraphicsClear($hGraphicsDest, 0xFFFFFFFF)

    $hPath = _GDIPlus_PathCreate()
    _GDIPlus_PathAddEllipse($hPath, 0, 0, $iX, $iY)

    _GDIPlus_GraphicsSetClipPath($hGraphicsDest, $hPath, 0)
    _GDIPlus_GraphicsDrawImage($hGraphicsDest, $hBitmapSource, 0, 0)
    _GDIPlus_ImageSaveToFile($hBitmapDest, @ScriptDir & "\" & $sImageDest)

    _GDIPlus_BitmapDispose($hBitmapSource)
    _GDIPlus_GraphicsDispose($hGraphicsDest)
    _GDIPlus_BitmapDispose($hBitmapDest)
    _GDIPlus_Shutdown()
EndFunc

So what am I doing wrong? Thanks.

 

 

 

 

 

Edited by Viet
Link to comment
Share on other sites

#include <GDIplus.au3>

clipCircle("96dpi.jpg", "96dpi_out.jpg")
clipCircle("300dpi.jpg", "300dpi_out.jpg")

clipCircle2("96dpi.jpg", "96dpi_out2.jpg")
clipCircle2("300dpi.jpg", "300dpi_out2.jpg")

Func clipCircle($sImageSource, $sImageDest)
    _GDIPlus_Startup()

    $hBitmapSource = _GDIPlus_BitmapCreateFromFile(@ScriptDir & "\" & $sImageSource)

    $hGraphicsSource = _GDIPlus_ImageGetGraphicsContext($hBitmapSource)
    _GDIPlus_GraphicsSetSmoothingMode($hGraphicsSource, $GDIP_SMOOTHINGMODE_HIGHQUALITY)

    $iX = _GDIPlus_ImageGetWidth($hBitmapSource)
    $iY = _GDIPlus_ImageGetHeight($hBitmapSource)

;~  Create an empty bitmap
;~  This does not work with 300 DPI images
    $hBitmapDest = _GDIPlus_BitmapCreateFromScan0($iX, $iY)

    ; New line : Fix DPI =====================================================================
    _GDIPlus_BitmapSetResolution($hBitmapDest, _GDIPlus_ImageGetHorizontalResolution($hBitmapSource), _GDIPlus_ImageGetVerticalResolution($hBitmapSource))

    $hGraphicsDest = _GDIPlus_ImageGetGraphicsContext($hBitmapDest)
    _GDIPlus_GraphicsSetSmoothingMode($hGraphicsDest, $GDIP_SMOOTHINGMODE_HIGHQUALITY)
    _GDIPlus_GraphicsClear($hGraphicsDest, 0xFFFFFFFF)

    $hPath = _GDIPlus_PathCreate()
    _GDIPlus_PathAddEllipse($hPath, 0, 0, $iX, $iY)

    _GDIPlus_GraphicsSetClipPath($hGraphicsDest, $hPath, 0)
    _GDIPlus_GraphicsDrawImage($hGraphicsDest, $hBitmapSource, 0, 0)

    ; New line ===============================================================================
    ; Improve Output Quality
    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

    ; New line ===============================================================================
    _GDIPlus_ImageSaveToFileEx($hBitmapDest, @ScriptDir & "\" & $sImageDest, $sImgCLSID, $tParams )

    _GDIPlus_GraphicsDispose($hGraphicsSource)
    _GDIPlus_BitmapDispose($hBitmapSource)
    _GDIPlus_GraphicsDispose($hGraphicsDest)
    _GDIPlus_BitmapDispose($hBitmapDest)
    _GDIPlus_Shutdown()
EndFunc

Func clipCircle2($sImageSource, $sImageDest)
    _GDIPlus_Startup()

    $hBitmapSource = _GDIPlus_BitmapCreateFromFile(@ScriptDir & "\" & $sImageSource)

    $iX = _GDIPlus_ImageGetWidth($hBitmapSource)
    $iY = _GDIPlus_ImageGetHeight($hBitmapSource)

;~  Clone the source bitmap
;~  This works regardless of the image's DPI
    $hBitmapDest = _GDIPlus_BitmapCloneArea($hBitmapSource, 0, 0, $iX, $iY)
    $hGraphicsDest = _GDIPlus_ImageGetGraphicsContext($hBitmapDest)
    _GDIPlus_GraphicsSetSmoothingMode($hGraphicsDest, $GDIP_SMOOTHINGMODE_HIGHQUALITY)
    _GDIPlus_GraphicsClear($hGraphicsDest, 0xFFFFFFFF)

    $hPath = _GDIPlus_PathCreate()
    _GDIPlus_PathAddEllipse($hPath, 0, 0, $iX, $iY)

    _GDIPlus_GraphicsSetClipPath($hGraphicsDest, $hPath, 0)
    _GDIPlus_GraphicsDrawImage($hGraphicsDest, $hBitmapSource, 0, 0)

    ; New line ===============================================================================
    ; Improve Output Quality
    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

    ; New line ===============================================================================
    _GDIPlus_ImageSaveToFileEx($hBitmapDest, @ScriptDir & "\" & $sImageDest, $sImgCLSID, $tParams )

    _GDIPlus_BitmapDispose($hBitmapSource)
    _GDIPlus_GraphicsDispose($hGraphicsDest)
    _GDIPlus_BitmapDispose($hBitmapDest)
    _GDIPlus_Shutdown()
EndFunc

; https://www.autoitscript.com/forum/topic/120163-set-pixels-per-inch-using-gdi/?do=findComment&comment=834906
; https://www.autoitscript.com/forum/topic/106021-gdipau3/
; #FUNCTION# ====================================================================================================================
; Name...........: _GDIPlus_BitmapSetResolution
; Description ...: Sets the resolution of this Bitmap object
; Syntax.........: _GDIPlus_BitmapSetResolution($hBitmap, $nDpiX, $nDpiY)
; Parameters ....: $hBitmap - Pointer to the Bitmap object
;   $nDpiX  - Value that specifies the horizontal resolution in dots per inch.
;   $nDpiX  - Value that specifies the vertical resolution in dots per inch.
; Return values .: Success  - True
;   Failure     - False and either:
;   |@error and @extended are set if DllCall failed
;   |$GDIP_STATUS contains a non zero value specifying the error code
; Remarks .......: None
; Related .......:
; Link ..........; @@MsdnLink@@ GdipBitmapSetResolution
; Example .......; Yes
; ===============================================================================================================================
Func _GDIPlus_BitmapSetResolution($hBitmap, $nDpiX, $nDpiY)
    Local $aResult = DllCall( $__g_hGDIPDll, "uint", "GdipBitmapSetResolution", "handle", $hBitmap, "float", $nDpiX, "float", $nDpiY)
    If @error Then Return SetError(@error, @extended, False)
    $GDIP_STATUS = $aResult[0]
    Return $aResult[0] = 0
EndFunc ;==>_GDIPlus_BitmapSetResolution

 

Edited by Synapsee
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...