Page 1 of 2

Get the height / width of an image - to an array (object)

Posted: 01 Oct 2020, 14:12
by Albireo
Intending to display an image with a AHK-GUI
Since I do not know how to scale an image with AHK GUI (I think it's impossible), I need to know the width and height of the image to be displayed to get structure on the entire GUI.

One way to get the size is to use IrfanView - Command line
Another way is to use gdip_all
Maybe there are better ways to do this on?

My wish is to create an object (selLogo) that contains information about the image. (eg. selLogo.name, selLogo.width, selLogo.height ...)
Tried to write a program below, but failed (in a way)
(selLogo is changed after the function call getImageSize(selLogo.name) and the selLogo.name is gone!)

Code: Select all

#NoEnv  ; Recommended for performance and compatibility with future AutoHotkey releases.
; #Warn  ; Enable warnings to assist with detecting common errors.
SendMode Input  ; Recommended for new scripts due to its superior speed and reliability.
SetWorkingDir %A_ScriptDir%  ; Ensures a consistent starting directory.
#SingleInstance force

#include gdip_all.ahk  ;  If it is not in your lib http://www.autohotkey.com/forum/topic32238.html

selLogo := []

FileSelectFile Logo, 3, C:\Users...\images, Select a imagefile, Images (*.jpg)
selLogo.name := Logo

selLogo := getImageSize(selLogo.name)
MsgBox ,, %A_ScriptName% - Row %A_LineNumber%, % "- " selLogo.Count() "`n- " selLogo.name "`n`nheight .: " selLogo.height "`nwidth .: " selLogo.width

ExitApp

getImageSize(imageFile)
{	; https://autohotkey.com/board/topic/61076-get-image-height-property-from-file-property-details/
	; lib .: gdip_all.ahk
	aImage := []
	
	If !pToken := Gdip_Startup()
	{	MsgBox, 48, gdiplus error!, Gdiplus failed to start. Please ensure you have gdiplus on your system
		ExitApp
	}
	
	pBitmap := Gdip_CreateBitmapFromFile(imageFile)
	Gdip_GetDimensions(pBitmap, width, height)
	Gdip_DisposeImage(pBitmap)
	Gdip_Shutdown(pToken)
	
	aImage.width := width
	aImage.height := height

	Return % aImage
}

Re: Get the height / width of an image - to an array (object)

Posted: 01 Oct 2020, 14:29
by mikeyww
GUI does scale. You can specify one dimension, and it will adjust the other.
To shrink or enlarge the image while preserving its aspect ratio, specify -1 for one of the dimensions and a positive number for the other. For example, specifying w200 h-1 would make the image 200 pixels wide and cause its height to be set automatically.
A little trick to find an image's size is below.

Code: Select all

imgWidth(img, ByRef height) { ; Get image's dimensions
 If FileExist(img) {
  GUI, Add, Picture, hwndpic, %img%
  ControlGetPos,,, width, height,, ahk_id %pic%
  Gui, Destroy
 } Else height := width := 0
 Return width
}

Re: Get the height / width of an image - to an array (object)  Topic is solved

Posted: 01 Oct 2020, 15:29
by teadrinker

Code: Select all

filePath := "D:\MyImage.jpg"
size := GetImageSize(filePath)
MsgBox, % size.W . "`n" size.H

GetImageSize(imageFilePath) {
   if !hBitmap := LoadPicture(imageFilePath, "GDI+")
      throw "Failed to load the image"
   VarSetCapacity(BITMAP, size := 4*4 + A_PtrSize*2, 0)
   DllCall("GetObject", "Ptr", hBitmap, "Int", size, "Ptr", &BITMAP)
   DllCall("DeleteObject", "Ptr", hBitmap)
   Return { W: NumGet(BITMAP, 4, "UInt"), H: NumGet(BITMAP, 8, "UInt") }
}

Re: Get the height / width of an image - to an array (object)

Posted: 01 Oct 2020, 15:35
by mikeyww
Very nice as well! It's handy to have the dimensions in an array.

Re: Get the height / width of an image - to an array (object)

Posted: 01 Oct 2020, 15:55
by Albireo
Thank you! (Nice solution)

My result

Code: Select all

#NoEnv  		; Recommended for performance and compatibility with future AutoHotkey releases.
SendMode Input 			; Recommended for new scripts due to its superior speed and reliability.
SetWorkingDir %A_ScriptDir%  	; Ensures a consistent starting directory.
#SingleInstance force

Logo := []

FileSelectFile LogoName, 3, C:\Users\...\images, Select a PDF-file, Images (*.jpg)
Logo.name := LogoName

Logo.width := imgWidth(Logo.name, height)
Logo.height := height

MsgBox ,, %A_ScriptName% - Row %A_LineNumber%, % "Logo.name .: " Logo.name "`nLogo.height .: " Logo.height "`nLogo.width .: " Logo.width
ExitApp

imgWidth(img, ByRef height) { ; Get image's dimensions
 If FileExist(img) {
  GUI, Add, Picture, hwndpic, %img%
  ControlGetPos,,, width, height,, ahk_id %pic%
  Gui, Destroy
 } Else height := width := 0
 Return width
}
About scale GUI (thank you! - again!)
a scale test of an image

Re: Get the height / width of an image - to an array (object)

Posted: 01 Oct 2020, 16:04
by mikeyww
Good! Here's the array version in case you like that.

Code: Select all

FileSelectFile LogoName, 3, C:\Users\...\images, Select an image file, Images (*.jpg; *.tif; *.bmp; *.jpeg; *.png; *.gif; *.tiff)
If FileExist(LogoName)
 MsgBox, 64, %A_ScriptName% - Row %A_LineNumber%
  , % Format("Name:  {}`nSize:    {} x {}", LogoName, (logo := imgSize(LogoName)).w, logo.h)
ExitApp

imgSize(img) { ; Get image's dimensions
 If FileExist(img) {
  GUI, Add, Picture, hwndpic, %img%
  ControlGetPos,,, width, height,, ahk_id %pic%
  Gui, Destroy
 }
 Return {w: width, h: height}
}

Re: Get the height / width of an image - to an array (object)

Posted: 01 Oct 2020, 16:05
by Albireo
the solution from @teadrinker
(easy to handle with an array)

Code: Select all

#NoEnv  ; Recommended for performance and compatibility with future AutoHotkey releases.
; #Warn  ; Enable warnings to assist with detecting common errors.
SendMode Input  ; Recommended for new scripts due to its superior speed and reliability.
SetWorkingDir %A_ScriptDir%  ; Ensures a consistent starting directory.
#SingleInstance force

Logo := []

FileSelectFile filePath, 3, A_ScripDir "\..", Select a PDF-file, Images (*.jpg)

size := GetImageSize(filePath)
MsgBox, % size.W . "`n" size.H

GetImageSize(imageFilePath) {
   if !hBitmap := LoadPicture(imageFilePath, "GDI+")
      throw "Failed to load the image"
   VarSetCapacity(BITMAP, size := 4*4 + A_PtrSize*2, 0)
   DllCall("GetObject", "Ptr", hBitmap, "Int", size, "Ptr", &BITMAP)
   DllCall("DeleteObject", "Ptr", hBitmap)
   Return { W: NumGet(BITMAP, 4, "UInt"), H: NumGet(BITMAP, 8, "UInt") }
}

Re: Get the height / width of an image - to an array (object)

Posted: 01 Oct 2020, 16:09
by Albireo
mikeyww wrote:
01 Oct 2020, 16:04
Good! Here's the array version in case you like that.
...
Also works well (you are good at handling Format())

Re: Get the height / width of an image - to an array (object)

Posted: 01 Oct 2020, 16:14
by BoBo
Stolen from here: http://autohotkey.com/board/topic/56987-com-object-reference-autohotkey-v11/?p=387238 (by sbc/@sbcglobal?)

Code: Select all

SplitPath,% USERPROFILE "\Pictures\DunningKruger.jpg", FileName, DirPath,

objShell		:= ComObjCreate("Shell.Application")
objFolder		:= objShell.NameSpace(DirPath)								; set the directry path
objFolderItem	:= objFolder.ParseName(FileName)							; set the file name
MsgBox % objFolder.GetDetailsOf(objFolderItem, 31)							; 31	= 'width x height'
MsgBox % StrSplit(objFolder.GetDetailsOf(objFolderItem, 176), A_Space).1	; 176	= '<width> Pixel'
MsgBox % StrSplit(objFolder.GetDetailsOf(objFolderItem, 178), A_Space).1	; 178	= '<height> Pixel'
Here limited to width & height. BTW, the original script delivers 29 image properties (and its descriptions) for my image :)

Re: Get the height / width of an image - to an array (object)

Posted: 01 Oct 2020, 16:19
by mikeyww
Very impressive!

I compared times of GUI vs. ComObj. Perhaps as expected, larger images favored ComObj, whereas smaller images favored GUI. On some runs, the GUI time measured was zero!

38 x 42 image: 78 ms for ComObj, 31 ms for GUI

676 x 1200 image: 78 ms for ComObj, 125 ms for GUI

Re: Get the height / width of an image - to an array (object)

Posted: 01 Oct 2020, 17:09
by BoBo
I've edited the code to skip the loop that would check for 283 optional properties/items and directly access the items that are of interest instead: width&height/width/height
That way ComObj is acting instantaneously (at least for me, myself and I).
For testing, I used/downloaded this photo: https://upload.wikimedia.org/wikipedia/commons/4/41/Sunflower_from_Silesia2.jpg (2434x1697) = 31/32ms and if using SetBatchLines, -1 = 15/16ms.

Re: Get the height / width of an image - to an array (object)

Posted: 01 Oct 2020, 17:23
by teadrinker
The last code doesn't actually get the picture size, it just reads metadata and shows what is wriiten there.

Re: Get the height / width of an image - to an array (object)

Posted: 01 Oct 2020, 17:31
by mikeyww
Sunflower with default SetBatchLines:

ComObj: 78 ms; wins again!

GUI: 530 ms

Re: Get the height / width of an image - to an array (object)

Posted: 01 Oct 2020, 17:36
by BoBo
@teadrinker Valid point. I've edited/shrank the test image. The script returned the new measurements correctly. So ...? :think:

Re: Get the height / width of an image - to an array (object)

Posted: 01 Oct 2020, 18:18
by teadrinker
Why not? It shows what you can see in file properties. 176 and 178 doesn't show width and hight for me, they show Folder Name and Location.

Re: Get the height / width of an image - to an array (object)

Posted: 01 Oct 2020, 19:52
by mikeyww
A puzzle.

Code: Select all

img = [pathToImage]
size := imgSize(img)
x := 10
n := size.w
sum := x + n
MsgBox, x='%x%' n='%n%' sum='%sum%'
ExitApp

imgSize(img) {
 SplitPath, img, fn, dir
 objShell := ComObjCreate("Shell.Application")
 objFolder := objShell.NameSpace(dir)
 objFolderItem := objFolder.ParseName(fn)
 scale := StrSplit(objFolder.GetDetailsOf(objFolderItem, 31), " x ")
 Return {w: scale.1, h: scale.2}
}
Yields:

x='10' n='‪58' sum=''

The GUI version does not have this issue. If I hard code the GetDetailsOf with something like "58 x 9", it works. It's especially bizarre because both x and n are correct. Further: Round(n) is 0. It's like it's showing "58", but it's not really 58; it's a different character set.

What is happening with the blank sum?

Re: Get the height / width of an image - to an array (object)

Posted: 01 Oct 2020, 20:44
by mikeyww
Fixed.

Code: Select all

imgSize(img) {
 SplitPath, img, fn, dir
 objShell := ComObjCreate("Shell.Application")
 objFolder := objShell.NameSpace(dir)
 objFolderItem := objFolder.ParseName(fn)
 scale := StrSplit(RegExReplace(objFolder.GetDetailsOf(objFolderItem, 31), ".(.+).", "$1"), " x ")
 Return {w: scale.1, h: scale.2}
}
Interesting to see the size flanked by control codes: ASCII 8234 and 8236.

Re: Get the height / width of an image - to an array (object)

Posted: 01 Oct 2020, 23:58
by SKAN
mikeyww wrote:
01 Oct 2020, 16:19
I compared times of GUI vs. ComObj. Perhaps as expected, larger images favored ComObj, whereas smaller images favored GUI. On some runs, the GUI time measured was zero!

38 x 42 image: 78 ms for ComObj, 31 ms for GUI

676 x 1200 image: 78 ms for ComObj, 125 ms for GUI
 
Fastest: IsPicture()

Re: Get the height / width of an image - to an array (object)

Posted: 02 Oct 2020, 03:40
by BoBo
@teadrinker
176 and 178 doesn't show width and hight for me, they show Folder Name and Location.
My output:
... what sbc's script is doing.
... after removing the condition. So in both cases it'll return 'Breite'/'width' at 176 and 'Höhe'/'height' at 178
That's WIS + WIG . :shifty:

@mikeyww - Confirmed that this sporadically has returned '0' for the same image + the output (if copied to clipboard, see my spoilered examples above) is showing/contains those characters, interestingly only for a few of its properties?!

Re: Get the height / width of an image - to an array (object)

Posted: 02 Oct 2020, 06:44
by mikeyww
Thanks for those test results and output!

I tested IsPicture(). It was initially impressive with a run time of zero ms. On further testing, it retrieved the wrong dimensions for one of my JPG files, so I'm not able to use it.