ImageMagick MagickWand API wrapper for resize image

Post your working scripts, libraries and tools.
taka
Posts: 2
Joined: 26 Jul 2023, 01:47

ImageMagick MagickWand API wrapper for resize image

Post by taka » 22 Aug 2023, 21:37

I'd like to share my result of ImageMagick MagickWand API wrapper for resize image.
It is only wrapped for my use case that is for resize, converting, identify image information.
This script needs dynamic of Image magick. I use "Win64 dynamic at 16 bits-per-pixel component" version.

I like this wrapper because webp and AVIF can be handled. And MagickWand API can get JPEG quality, frame count of animation image easily.
I'm grad if you like it.

Code: Select all

; ===================================================================================================================
; Load and initialize Core_RL_MagickWand_.dll which is supposed to be in PATH environment variable.
; Parameters:    LibPath  - Optional: Absolute path of Core_RL_MagickWand_.dll
; ===================================================================================================================
loadMagickWandAPI(LibPath := "") {
	Static LibMagickWand := "Core_RL_MagickWand_.dll"
	; Load Core_RL_MagickWand_.dll
	If (LibPath)
		LibMagickWand := LibPath
	If !(MagickWandModule := DllCall("Kernel32.dll\LoadLibrary", "Str", LibMagickWand, "UPtr")) {
		If (A_LastError = 126) ; The specified module could not be found
			MsgBox("Could not find " LibMagickWand "!", "MagickWand Error!", 16)
		Else {
			ErrCode := A_LastError
			ErrMsg := Buffer(131072, 0) ; Unicode ; V1toV2: if 'ErrMsg' is a UTF-16 string, use 'VarSetStrCapacity(&ErrMsg, 131072)'
			DllCall("FormatMessage", "UInt", 0x1200, "Ptr", 0, "UInt", ErrCode, "UInt", 0, "Str", ErrMsg, "UInt", 65536, "Ptr", 0)
			MsgBox("Could not load " . LibMagickWand . "!`n"									. "Error code: " . ErrCode . "`n"									. ErrMsg, "MagickWand Error!", 16)
		}
		Return False
	}
	MagickWandGenesis()
	if (IsMagickWandInstantiated() == False) {
		Return 0 
	}

	Return MagickWandModule
}

; ===================================================================================================================
; unload and clear Core_RL_MagickWand_.dll
; ===================================================================================================================
unloadMagickWandAPI(Module)
{
	MagickWandTerminus()
	If (Module)
		DllCall("Kernel32.dll\FreeLibrary", "Ptr", Module)
}

; ===================================================================================================================
; https://imagemagick.org/api/magick-wand.php#MagickWandGenesis
; void MagickWandGenesis(void)
; MagickWandGenesis() initializes the MagickWand environment.
; ===================================================================================================================
MagickWandGenesis()
{
	Return DllCall("Core_RL_MagickWand_.dll\MagickWandGenesis", "Int")
}	

; ===================================================================================================================
; https://imagemagick.org/api/magick-wand.php#MagickWandTerminus
; void MagickWandTerminus(void)
; MagickWandTerminus() terminates the MagickWand environment.
; ===================================================================================================================
MagickWandTerminus()
{
	Return DllCall("Core_RL_MagickWand_.dll\MagickWandTerminus", "Int")
}

; ===================================================================================================================
; https://imagemagick.org/api/magick.php#IsMagickWandInstantiated
; MagickBooleanType IsMagickWandInstantiated(void)
; ===================================================================================================================
IsMagickWandInstantiated()
{
	Return DllCall("Core_RL_MagickWand_.dll\IsMagickWandInstantiated", "Int")
}

; ===================================================================================================================
; https://imagemagick.org/api/magick-wand.php#MagickGetException
; char *MagickGetException(const MagickWand *wand,ExceptionType *severity)
; ===================================================================================================================
MagickGetException(Wand, &Severity)
{
	; ImageMagick uses UTF-8 encode for error message string other than ASCII string
	errmsg := DllCall("Core_RL_MagickWand_.dll\MagickGetException", "Ptr", Wand, "Ptr*", &Severity, "Str")
	Return StrGet(errmsg, "UTF-8")
}

; ===================================================================================================================
; https://imagemagick.org/api/magick-wand.php#NewMagickWand
; NewMagickWand() returns a wand required for all other methods in the API. 
; A fatal exception is thrown if there is not enough memory to allocate the wand. 
; Use DestroyMagickWand() to dispose of the wand when it is no longer needed.
; MagickWand *NewMagickWand(void)
; ===================================================================================================================
NewMagickWand()
{
	Return DllCall("Core_RL_MagickWand_.dll\NewMagickWand", "Ptr")
}

; ===================================================================================================================
; https://imagemagick.org/api/magick-wand.php#DestroyMagickWand
; MagickWand *DestroyMagickWand(MagickWand *wand)
; ===================================================================================================================
DestroyMagickWand(wand)
{
	Return DllCall("Core_RL_MagickWand_.dll\DestroyMagickWand", "Ptr", wand, "Ptr")
}

; ===================================================================================================================
; https://imagemagick.org/api/magick-wand.php#IsMagickWand
; MagickBooleanType IsMagickWand(const MagickWand *wand)
; ===================================================================================================================
IsMagickWand(wand)
{
	Return DllCall("Core_RL_MagickWand_.dll\IsMagickWand", "Ptr", Wand, "Int")
}

; ===================================================================================================================
; https://imagemagick.org/api/magick-image.php#MagickReadImage
; MagickBooleanType MagickReadImage(MagickWand *wand,const char *filename)
; ===================================================================================================================
MagickReadImage(wand, filename)
{
	; ImageMagick needs to use UTF-8 encode for characters other than ASCII string
	fname := Buffer(StrPut(filename, "UTF-8"))
	StrPut(filename, fname, "UTF-8")
	Return DllCall("Core_RL_MagickWand_.dll\MagickReadImage", "Ptr", wand, "Ptr", fname, "Int")
}

; ===================================================================================================================
; https://imagemagick.org/api/magick-image.php#MagickPingImage
; MagickBooleanType MagickPingImage(MagickWand *wand,const char *filename)
; ===================================================================================================================
MagickPingImage(wand, filename)
{
	; ImageMagick needs to use UTF-8 encode for characters other than ASCII string
	fname := Buffer(StrPut(filename, "UTF-8"))
	StrPut(filename, fname, "UTF-8")
	Return DllCall("Core_RL_MagickWand_.dll\MagickPingImage", "Ptr", wand, "Ptr", fname, "Int")
}

; ===================================================================================================================
; https://imagemagick.org/api/magick-image.php#MagickWriteImage
; MagickBooleanType MagickWriteImage(MagickWand *wand, const char *filename)
; ===================================================================================================================
MagickWriteImage(wand, filename)
{
	; ImageMagick needs to use UTF-8 encode for characters other than ASCII string
	fname := Buffer(StrPut(filename, "UTF-8"))
	StrPut(filename, fname, "UTF-8")
	Return DllCall("Core_RL_MagickWand_.dll\MagickWriteImage", "Ptr", wand, "Ptr", fname, "Int")
}

; ===================================================================================================================
; https://imagemagick.org/api/magick-image.php#MagickResizeImage
; MagickBooleanType MagickResizeImage(MagickWand *wand, const size_t columns,const size_t rows,const FilterType filter)
; filter options:
;   UndefinedFilter = 0
;   PointFilter = 1
;   BoxFilter = 2
;   TriangleFilter = 3
;   HermiteFilter = 4
;   HannFilter = 5
;   HammingFilter = 6
;   BlackmanFilter = 7
;   GaussianFilter = 8
;   QuadraticFilter = 9
;   CubicFilter = 10
;   CatromFilter = 11
;   MitchellFilter = 12
;   JincFilter = 13
;   SincFilter = 14
;   SincFastFilter = 15
;   KaiserFilter = 16
;   WelchFilter = 17
;   ParzenFilter = 18
;   BohmanFilter = 19
;   BartlettFilter = 20
;   LagrangeFilter = 21
;   LanczosFilter = 22
;   LanczosSharpFilter = 23
;   Lanczos2Filter = 24
;   Lanczos2SharpFilter = 25
;   RobidouxFilter = 26
;   RobidouxSharpFilter = 27
;   CosineFilter = 28
;   SplineFilter = 29
;   LanczosRadiusFilter = 30
;   CubicSplineFilter = 31
; ===================================================================================================================
MagickResizeImage(wand, columns, rows, filter)
{
	Return DllCall("Core_RL_MagickWand_.dll\MagickResizeImage", "Ptr", wand, "UPtr", columns, "UPtr", rows, "Int", filter, "Int")
}

; ===================================================================================================================
; https://imagemagick.org/api/magick-image.php#MagickUnsharpMaskImage
; MagickBooleanType MagickUnsharpMaskImage(MagickWand *wand, const double radius,const double sigma,const double gain, const double threshold)
; ===================================================================================================================
MagickUnsharpMaskImage(wand, radius:=0.0, sigma:=1.0, gain:=1.0, threshold:=0.05)
{
	Return DllCall("Core_RL_MagickWand_.dll\MagickUnsharpMaskImage", "Ptr", wand, "Double", radius, "Double", sigma, "Double", gain, "Double", threshold, "Int")
}

; ===================================================================================================================
; https://imagemagick.org/api/magick-image.php#MagickSetImageCompressionQuality
; MagickBooleanType MagickSetImageCompressionQuality(MagickWand *wand, const size_t quality)
; ===================================================================================================================
MagickSetImageCompressionQuality(wand, quality)
{
	Return DllCall("Core_RL_MagickWand_.dll\MagickSetImageCompressionQuality", "Ptr", wand, "UPtr", quality, "Int")
}

; ===================================================================================================================
; https://imagemagick.org/api/magick-image.php#MagickGetImageWidth
; size_t MagickGetImageWidth(MagickWand *wand)
; ===================================================================================================================
MagickGetImageWidth(wand)
{
	Return DllCall("Core_RL_MagickWand_.dll\MagickGetImageWidth", "Ptr", wand, "UPtr")
}

; ===================================================================================================================
; https://imagemagick.org/api/magick-image.php#MagickGetImageHeight
; size_t MagickGetImageHeight(MagickWand *wand)
; ===================================================================================================================
MagickGetImageHeight(wand)
{
	Return DllCall("Core_RL_MagickWand_.dll\MagickGetImageHeight", "Ptr", wand, "UPtr")
}

; ===================================================================================================================
; https://imagemagick.org/api/magick-image.php#MagickGetImageCompressionQuality
; size_t MagickGetImageCompressionQuality(MagickWand *wand)
; ===================================================================================================================
MagickGetImageCompressionQuality(wand)
{
	Return DllCall("Core_RL_MagickWand_.dll\MagickGetImageCompressionQuality", "Ptr", wand, "UPtr")
}

; ===================================================================================================================
; https://imagemagick.org/api/magick-image.php#MagickGetNumberImages
; size_t MagickGetNumberImages(MagickWand *wand)
; ===================================================================================================================
MagickGetNumberImages(wand)
{
	Return DllCall("Core_RL_MagickWand_.dll\MagickGetNumberImages", "Ptr", wand, "UPtr")
}

; ===================================================================================================================
; https://imagemagick.org/api/magick-image.php#MagickGetImageOrientation
; OrientationType  MagickGetImageOrientation(MagickWand *wand)
; OrientationType value:
;   UndefinedOrientation = 0
;   TopLeftOrientation = 1		Normal
;   TopRightOrientation = 2		Flip horizontal
;   BottomRightOrientation = 3	Rotation (180 degree)
;   BottomLeftOrientation = 4	Rotation (180 degree) + flip horizontal
;   LeftTopOrientation = 5		Rotation (90 degree) + flip horizontal
;   RightTopOrientation = 6		Rotation (90 degree)
;   RightBottomOrientation = 7	Rotation (270 degree) + Flip horizontal
;   LeftBottomOrientatio = 8	Rotation (270 degree)
; ===================================================================================================================
MagickGetImageOrientation(wand)
{
	Return DllCall("Core_RL_MagickWand_.dll\MagickGetImageOrientation", "Ptr", wand, "Int")
}

Sample program for how to use MagickWand wrapper
In this sample script, I don't specify Core_RL_MagickWand_.dll path at loadMagickWandAPI call because my environment set PATH for ImageMagick.
If your environment doesn't set PATH for ImageMagick, prease specify Core_RL_MagickWand_.dll PATH at loadMagickWandAPI call.

Code: Select all

#Requires AutoHotkey v2.0+

OnExit(ExitSub, )

dir := A_ScriptDir "\"

MagickWandModule := loadMagickWandAPI()
If (!MagickWandModule) {
	MsgBox("Failed to load/initialize ImageMagick library `"Core_RL_MagickWand_.dll`"")
	ExitApp()
}

IMResize(dir "IMG_0468.JPG", dir "IMG_0468-25.JPG", 25)

ExitApp

;Terminate the MagickWand environment.
ExitSub(A_ExitReason, ExitCode)
{
	unloadMagickWandAPI(MagickWandModule)
	ExitApp()
}


IMResize(infname, outfname, filter)
{
	Wand := NewMagickWand()
	if (MagickPingImage(Wand, infname) = 0){
		errmsg := MagickGetException(Wand, &Severity)
		MsgBox("MagickPingImage error(" Severity "): " errmsg)
		Return
	}
	width := MagickGetImageWidth(Wand)
	height := MagickGetImageHeight(Wand)
	quality := MagickGetImageCompressionQuality(Wand)
	framecount := MagickGetNumberImages(Wand)
	orientation := MagickGetImageOrientation(Wand)
	width := Round(0.5*width)
	height := Round(0.5*height)
	if (MagickReadImage(Wand, infname) = 0){
		errmsg := MagickGetException(Wand, &Severity)
		MsgBox("MagickReadImage error(" Severity "): " errmsg)
		Return
	}
	MagickResizeImage(Wand, width, height, filter)
	MagickSetImageCompressionQuality(Wand, 80)
	MagickWriteImage(Wand, outfname)
	Wand := DestroyMagickWand(Wand)
}

Return to “Scripts and Functions (v2)”