[Function] Resize and Convert Images

Post your working scripts, libraries and tools for AHK v1.1 and older
kon
Posts: 1756
Joined: 29 Sep 2013, 17:11

[Function] Resize and Convert Images

01 Mar 2014, 15:30

[Function] - ResConImg()
Resize and Convert Images

About:
Resize and convert image files (png, bmp, jpg, tiff, or gif).
Gdip must be started before the function is called, like in the example scripts below.
Requires:
Gdip.ahk either #Included or in your Lib folder.
Function:

Code: Select all

/*  ResConImg
 *    By kon
 *    Updated November 2, 2015
 *    http://ahkscript.org/boards/viewtopic.php?f=6&t=2505&p=13640#p13640
 *
 *  Resize and convert images. png, bmp, jpg, tiff, or gif.
 *
 *  Requires Gdip.ahk in your Lib folder or #Included. Gdip.ahk is available at:
 *      http://www.autohotkey.com/board/topic/29449-gdi-standard-library-145-by-tic/
 *     
 *  ResConImg( OriginalFile             ;- Path of the file to convert
 *           , NewWidth                 ;- Pixels (Blank = Original Width)
 *           , NewHeight                ;- Pixels (Blank = Original Height)
 *           , NewName                  ;- New file name (Blank = "Resized_" . OriginalFileName)
 *           , NewExt                   ;- New file extension can be png, bmp, jpg, tiff, or gif (Blank = Original extension)
 *           , NewDir                   ;- New directory (Blank = Original directory)
 *           , PreserveAspectRatio      ;- True/false (Blank = true)
 *           , BitDepth)                ;- 24/32 only applicable to bmp file extension (Blank = 24)
 */
ResConImg(OriginalFile, NewWidth:="", NewHeight:="", NewName:="", NewExt:="", NewDir:="", PreserveAspectRatio:=true, BitDepth:=24) {
    SplitPath, OriginalFile, SplitFileName, SplitDir, SplitExtension, SplitNameNoExt, SplitDrive
    pBitmapFile := Gdip_CreateBitmapFromFile(OriginalFile)                  ; Get the bitmap of the original file
    Width := Gdip_GetImageWidth(pBitmapFile)                                ; Original width
    Height := Gdip_GetImageHeight(pBitmapFile)                              ; Original height
    NewWidth := NewWidth ? NewWidth : Width
    NewHeight := NewHeight ? NewHeight : Height
    NewExt := NewExt ? NewExt : SplitExtension
    if SubStr(NewExt, 1, 1) != "."                                          ; Add the "." to the extension if required
        NewExt := "." NewExt
    NewPath := ((NewDir != "") ? NewDir : SplitDir)                         ; NewPath := Directory
            . "\" ((NewName != "") ? NewName : "Resized_" SplitNameNoExt)       ; \File name
            . NewExt                                                            ; .Extension
    if (PreserveAspectRatio) {                                              ; Recalcultate NewWidth/NewHeight if required
        if ((r1 := Width / NewWidth) > (r2 := Height / NewHeight))          ; NewWidth/NewHeight will be treated as max width/height
            NewHeight := Height / r1
        else
            NewWidth := Width / r2
    }
    pBitmap := Gdip_CreateBitmap(NewWidth, NewHeight                        ; Create a new bitmap
    , (SubStr(NewExt, -2) = "bmp" && BitDepth = 24) ? 0x21808 : 0x26200A)   ; .bmp files use a bit depth of 24 by default
    G := Gdip_GraphicsFromImage(pBitmap)                                    ; Get a pointer to the graphics of the bitmap
    Gdip_SetSmoothingMode(G, 4)                                             ; Quality settings
    Gdip_SetInterpolationMode(G, 7)
    Gdip_DrawImage(G, pBitmapFile, 0, 0, NewWidth, NewHeight)               ; Draw the original image onto the new bitmap
    Gdip_DisposeImage(pBitmapFile)                                          ; Delete the bitmap of the original image
    Gdip_SaveBitmapToFile(pBitmap, NewPath)                                 ; Save the new bitmap to file
    Gdip_DisposeImage(pBitmap)                                              ; Delete the new bitmap
    Gdip_DeleteGraphics(G)                                                  ; The graphics may now be deleted
}
Example Usage:
This example will create a copy of "test.png" named "Resized_test.png".

Code: Select all

If !pToken := Gdip_Startup() {  ; Start Gdip
    MsgBox, 16, Gdiplus Error, Gdiplus failed to start.
    ExitApp
}
FilePath := A_Desktop "\test.png"
if FileExist(FilePath)
    ResConImg(FilePath, 1366, 768,,,, false)
else
    MsgBox, 16, File Error, File not found.
Gdip_Shutdown(pToken)  ; Close Gdip
This example will resize images dropped onto a Gui.

Code: Select all

#SingleInstance, Force
#NoEnv
SetBatchLines, -1
OnExit, Exit
; Uncomment if Gdip.ahk is not in your standard library
;#Include, Gdip.ahk
If !pToken := Gdip_Startup() {  ; Start Gdip
    MsgBox, 48, gdiplus error!, Gdiplus failed to start. Please ensure you have Gdip.ahk on your system.
    ExitApp
}
FileSelectFolder, SelectedFolder, % A_Desktop, 3, Select a directory in which to save the resized image(s).
if (ErrorLevel)
    ExitApp
Gui, Add, Text, , Drag and drop images to resize.
Gui, Show, H200 W200
return

GuiDropFiles:
Loop, parse, A_GuiEvent, `n
    ResConImg(A_LoopField, 800, 600, , , SelectedFolder)
return

Esc::
GuiClose:
Exit:
Gdip_Shutdown(pToken)
ExitApp
Thanks to tic for Gdip.ahk.
This function is similar to, but not based on, tic's ConvertImage(). I didn't search for other functions until after I had coded this, and I was unable to locate the source code for tic's version.
Users may also be interested in Learning one's Resize/Rotate/Crop/Clone functions.

Changes Log
Spoiler
Last edited by kon on 24 Sep 2016, 14:21, edited 7 times in total.
User avatar
noname
Posts: 515
Joined: 19 Nov 2013, 09:15

Re: [Function] Resize and Convert Images

05 Mar 2014, 10:25

Very nice it would replace irfanview commandline for resizing. :)


I have two remarks:
  • to get consistent quality resizing i would include two gdip commands
    Gdip_SetSmoothingMode(G, 4)
    Gdip_SetInterpolationMode(G, 7)
  • resizing a 24bit bmp is saved as 32bit which is a lot bigger ,irfanview leaves it as 24bit
Thanks for posting.
kon
Posts: 1756
Joined: 29 Sep 2013, 17:11

Re: [Function] Resize and Convert Images

05 Mar 2014, 16:15

Thanks for the feedback noname. :)

The function has been updated to include your suggestions and some other changes also.
  • Added Gdip_SetSmoothingMode and Gdip_SetInterpolationMode
  • Added another optional parameter which is only applicable to files saved as bmp. bmp files will be saved as 24bit by default, specify 32 if desired
  • Changed parameter order, moved "OriginalFile" to first parameter
  • NewWidth and/or NewHeight can now be left blank in which case the original dimensions will be used
User avatar
Chef
Posts: 50
Joined: 14 Nov 2013, 13:01

Re: [Function] Resize and Convert Images

06 Mar 2014, 20:46

Nice, can you make it convert to ICO?
kon
Posts: 1756
Joined: 29 Sep 2013, 17:11

Re: [Function] Resize and Convert Images

07 Mar 2014, 14:14

Chef wrote:Nice, can you make it convert to ICO?
I'm looking into it. My initial impression is that conversion to ICO is best left as a separate function because the conversion process is vastly different. So far I've found ICO creater/converter (.PNG to .ICO) by Rseding91.
garry
Posts: 3770
Joined: 22 Dec 2013, 12:50

Re: [Function] Resize and Convert Images

08 Mar 2014, 04:45

like to use also freeware commandline irfanview , my default picture viewer ( convert , resize , crop, printscreen etc ... )
example make an ico from picture

Code: Select all

;-- example Drag & Drop picture  with freeware Irfanview
;-- use commandlines to convert / resize etc Pictures/Photos's

modified=20140225
;- irfanview drag&drop resize convert
;- http://www.irfanview.com/

filename1=Irfanview_Drag&Drop convert resize
PR=%A_ProgramFiles%\IrfanView\i_view32.exe

Gui,2: Font, default, FixedSys
Gui,2:add,button  , x840 y15 h22 w100  gStart1       ,Start
Gui,2:Show, x50 y10 w970 h50,%Filename1%
Gui,2:add,edit    , x10 y10 h35 w820   vF1,Drag&Drop picture here
return

2Guiclose:
exitapp

start1:
Gui,2:submit,nohide
guicontrolget,F1
SplitPath, F1, name, dir, ext, name_no_ext, drive
If Ext Not In jpg,bmp,tif
{
msgbox, 262192, Picture MESSAGE,Only pictures tif bmp jpg
return
}

;-- resize a picture
;new=%a_scriptdir%\%name_no_ext%_new.%ext%
;aa=/resize=(800,0) /aspectratio /convert=%new%

;- convert to pdf -------
;new=%a_scriptdir%\%name_no_ext%_new.pdf
;aa=/convert=%new%

;- convert to ico -------
new=%a_desktop%\%name_no_ext%_new.ico
;aa= /aspectratio /resize=(138`,0) /gray /convert=%new%
aa= /aspectratio /resize=(138`,0) /convert=%new%

runwait,%pr% %f1% %aa%

ifexist,%new%
    run,%new%
return


2GuiDropFiles:
GuiControl,2:,F1
Loop, parse, A_GuiEvent, `n
   GuiControl,2:,F1,%A_LoopField%
return
;=============== end script ==============
User avatar
Chef
Posts: 50
Joined: 14 Nov 2013, 13:01

Re: [Function] Resize and Convert Images

08 Mar 2014, 22:34

Nothing comes even close to ImageMagick.
kon
Posts: 1756
Joined: 29 Sep 2013, 17:11

Re: [Function] Resize and Convert Images

09 Mar 2014, 05:48

Here's my first attempt at a function to create ICO files.
It's based on ICO creater/converter (.PNG to .ICO) by Rseding91, but will also convert and resize the images that are passed to it.

Code: Select all

#SingleInstance, Force
#NoEnv
SetBatchLines, -1
Gui, Add, Text, , Drag and drop images to create icons.
Gui, Show, H200 W200
return

GuiDropFiles:
Loop, parse, A_GuiEvent, `n
{
	i++
	ImageArray := []
	ImageArray[1] := [A_LoopField, 128, 128]
	ImageArray[2] := [A_LoopField, 64, 64]
	ImageArray[3] := [A_LoopField, 32, 32]
	ImageArray[4] := [A_LoopField, 16, 16]
	ResConICO(ImageArray, "MyIcon" i ".ico", A_Desktop)
}
return

GuiClose:
ExitApp

; Based on (Large parts are directly from):
; http://www.autohotkey.com/board/topic/82416-ico-createrconverter-png-to-ico/
; http://www.autohotkey.net/~Rseding91/ICO%20Converter/ICO%20Converter.ahk
ResConICO(ImageArray, NewName, NewDir) {
	ICO_ContainerSize := 16
	, O := 0
	, Total_PotentialSize := 6
	, pToken := Gdip_Startup()
		
	; Convert Images
	for i, img in ImageArray {
		pBitmapFile := Gdip_CreateBitmapFromFile(img[1])							; Get a bitmap of the file to convert
		, pBitmap := Gdip_CreateBitmap(img[2], img[3])								; Create a new bitmap of the desired width/heigh
		, G := Gdip_GraphicsFromImage(pBitmap)                                  	; Get a pointer to the graphics of the bitmap
		, Gdip_SetSmoothingMode(G, 4)												; Set image quality modes
		, Gdip_SetInterpolationMode(G, 7)
		, Gdip_DrawImage(G, pBitmapFile, 0, 0, img[2], img[3])            		 	; Draw the original image onto the new bitmap
		, Gdip_DisposeImage(pBitmapFile)                                        	; Delete the bitmap of the original image
		, Gdip_SaveBitmapToFile(pBitmap, A_ScriptDir "\TempResized" i ".png")       ; Save the new bitmap to file
		, Gdip_DisposeImage(pBitmap)                                            	; Delete the new bitmap
		, Gdip_DeleteGraphics(G)                                               		; The graphics may now be deleted
		, img[1] := A_ScriptDir "\TempResized" i ".png"
		FileGetSize, ImgSize, % img[1]
		if (ImgSize)
			Total_PotentialSize += ICO_ContainerSize + ImgSize
	}

	VarSetCapacity(ICO_Data, Total_PotentialSize, 0)
	, NumPut(0, ICO_Data, O, "UShort"), O += 2 ;reserved - always 0
	, NumPut(1, ICO_Data, O, "UShort"), O += 2 ;ico = 1, cur = 2
	, NumPut(0, ICO_Data, O, "UShort"), O += 2 ;number of images in file
	
	for i, img in ImageArray {
		if (img[2] < 257 && img[3] < 257 && File := FileOpen(img[1], "r")) {
			NumPut(img[2], ICO_Data, O, "UChar"), O += 1 ;image width: 256 = 0
			, NumPut(img[3], ICO_Data, O, "UChar"), O += 1 ;image height: 256 = 0
			, NumPut(0, ICO_Data, O, "UChar"), O += 1 ;color palatte: 0 if not used
			, NumPut(0, ICO_Data, O, "UChar"), O += 1 ;reserved - always 0
			, NumPut(0, ICO_Data, O, "UShort"), O += 2 ;ico - color planes (0/1), cur - horizontal coordinates of the hotspot in pixels from left
			, NumPut(32, ICO_Data, O, "UShort"), O += 2 ;ico - bits per pixel, cur - vertical coordinates of hotspot in pixels from top
			, NumPut(File.Length, ICO_Data, O, "UInt"), O += 4 ;Size of image data in bytes
			, NumPut(O + 4, ICO_Data, O, "UInt"), O += 4 ;Offset of image data from begining of ico/cur file
			, File.RawRead(&ICO_Data + O, File.Length)
			, O += File.Length
			, NumPut(NumGet(ICO_Data, 4, "UShort") + 1, ICO_Data, 4, "UShort") ;Adds one to the total number of images
			, File.Close()
		}
		FileDelete, % img[1]
	}

	If (O > 6){
		File := FileOpen(NewDir "\" NewName, "w")
		, File.RawWrite(&ICO_Data, O)
		, File.Close()
		, VarSetCapacity(ICO_Data, O, 0)
		, VarSetCapacity(ICO_Data, 0)
	}
	Gdip_Shutdown(pToken)
}
User avatar
noname
Posts: 515
Joined: 19 Nov 2013, 09:15

Re: [Function] Resize and Convert Images

09 Mar 2014, 10:17

ResConImg Great! It can become a "classic" :)

You have included "pToken := Gdip_Startup()" inside the function in your latest resconico().Did you try this also in resconimg()?

I have been testing this and there is no real speed impact when you have lots of files but i had to change the "Gdip_Shutdown(pToken)" to "DllCall("gdiplus\GdiplusShutdown", "uint", pToken)" because otherwise it crashed at the end (the images where converted correctly).

I was wondering if you had a similar problem because it is more convenient to have it inside the function.
tmplinshi
Posts: 1604
Joined: 01 Oct 2013, 14:57

Re: [Function] Resize and Convert Images

22 Jul 2015, 22:36

Thanks. You saved my time :)
tmplinshi
Posts: 1604
Joined: 01 Oct 2013, 14:57

Re: [Function] Resize and Convert Images

31 Oct 2015, 10:24

A small bug:
, NewPath := (NewDir ? NewDir : SplitDir) ; NewPath := Directory
. "\" (NewName ? NewName : "Resized_" SplitNameNoExt) ; \File name
It will causing 0 or 0000 treated as blank.

Change to this would be better:
, NewPath := ((NewDir!="") ? NewDir : SplitDir) ; NewPath := Directory
. "\" ((NewName!="") ? NewName : "Resized_" SplitNameNoExt) ; \File name
kon
Posts: 1756
Joined: 29 Sep 2013, 17:11

Re: [Function] Resize and Convert Images

02 Nov 2015, 15:52

noname wrote:ResConImg Great! It can become a "classic" :)

You have included "pToken := Gdip_Startup()" inside the function in your latest resconico().Did you try this also in resconimg()?

I have been testing this and there is no real speed impact when you have lots of files but i had to change the "Gdip_Shutdown(pToken)" to "DllCall("gdiplus\GdiplusShutdown", "uint", pToken)" because otherwise it crashed at the end (the images where converted correctly).

I was wondering if you had a similar problem because it is more convenient to have it inside the function.
Thanks noname. Sorry for the incredibly late reply. I didn't reply before because I don't know the answer to your question. Although, I do remember investigating it a bit when you initially posted this question. My best guess at the time was that the higher speed of ResConImg was causing the instability. ie: gdip wasn't fully shutdown before it was started again. It now seems like a bad idea to potentially load and unload gdip many times, even in ResConIco. It's probably best to let other users decide how and when to startup/shutdown gdip.
tmplinshi wrote:A small bug:
, NewPath := (NewDir ? NewDir : SplitDir) ; NewPath := Directory
. "\" (NewName ? NewName : "Resized_" SplitNameNoExt) ; \File name
It will causing 0 or 0000 treated as blank.

Change to this would be better:
, NewPath := ((NewDir!="") ? NewDir : SplitDir) ; NewPath := Directory
. "\" ((NewName!="") ? NewName : "Resized_" SplitNameNoExt) ; \File name
Thanks for reporting the bug tmplinshi. I've updated the function with your suggestion.
skrommel
Posts: 17
Joined: 15 Sep 2014, 06:15

Re: [Function] Resize and Convert Images

07 Sep 2017, 17:16

Why can't I add a 256x265 icon to kon's script?

By adding
ImageArray[1] := [A_LoopField, 256, 256]
ImageArray[2] := [A_LoopField, 128, 128]
ImageArray[3] := [A_LoopField, 64, 64]
ImageArray[4] := [A_LoopField, 32, 32]
ImageArray[5] := [A_LoopField, 16, 16]
an icon is created, with a working 256x256 thumbnail preview, but Windows says it doesn't contain any icons when I try to use it.

I've also tried changing
NumPut(img[2], ICO_Data, O, "UChar"), O += 1 ;image width: 256 = 0
, NumPut(img[3], ICO_Data, O, "UChar"), O += 1 ;image height: 256 = 0
to zero, but still no luck.

If I only add
ImageArray[1] := [A_LoopField, 256, 256]
a working 256x256 icon is created.

Any suggestions, anyone?
Last edited by skrommel on 08 Sep 2017, 02:38, edited 3 times in total.
User avatar
jeeswg
Posts: 6902
Joined: 19 Dec 2016, 01:58
Location: UK

Re: [Function] Resize and Convert Images

07 Sep 2017, 17:25

Just thought I'd mention you have ImageArray[1] twice there, in case it's that.
homepage | tutorials | wish list | fun threads | donate
WARNING: copy your posts/messages before hitting Submit as you may lose them due to CAPTCHA
skrommel
Posts: 17
Joined: 15 Sep 2014, 06:15

Re: [Function] Resize and Convert Images

08 Sep 2017, 02:36

Sadly, no, jeeswg, just a typo in the post. :roll:
ahkrpa
Posts: 17
Joined: 16 Apr 2019, 17:34

Re: [Function] Resize and Convert Images

04 May 2019, 10:00

kon... Thank you for this function.
User avatar
elModo7
Posts: 217
Joined: 01 Sep 2017, 02:38
Location: Spain
Contact:

Re: [Function] Resize and Convert Images

07 May 2019, 03:10

Amazing Function! thanks for the bump and thanks to kon and everyone involved in this!
User avatar
SirSocks
Posts: 360
Joined: 26 Oct 2018, 08:14

Re: [Function] Resize and Convert Images

14 Apr 2020, 12:01

Can this function be modified to keep the original EXIF data? It's lost when the image is resized. :think:
blue83
Posts: 157
Joined: 11 Apr 2018, 06:38

Re: [Function] Resize and Convert Images

16 Apr 2020, 03:38

Hi @kon

How to add canvas size to image?

thanks,
blue

EDIT: I have found it

https://autohotkey.com/board/topic/51035-add-border-on-images/
User avatar
iilabs
Posts: 296
Joined: 07 Jun 2020, 16:57

Re: [Function] Resize and Convert Images

09 Nov 2020, 14:28

Does anyone know how I would resize an image saved in clipboard and when pasted converts to smaller size? I like this clipper since very small size. Would be nice to see lines in multimonitor if someone could help guide me? Thanks!

Code: Select all

F3::                                                 ;Hold F3 to make a selection, then release
{
MouseGetPos, x1, y1
SoundBeep, 1500, 20
KeyWait, %A_ThisHotkey%
SoundBeep, 1000, 20
MouseGetPos, x2, y2
width := x2 - x1, height := y2 - y1
If (width < 4 && height < 4)
 Return
pToken := Gdip_Startup(), snap := Gdip_BitmapFromScreen(x1 "|" y1 "|" width "|" height)
Gdip_SetBitmapToClipboard(snap), Gdip_SaveBitmapToFile(snap, out)
Gdip_DisposeImage(snap), Gdip_Shutdown(pToken)
}
Return

Return to “Scripts and Functions (v1)”

Who is online

Users browsing this forum: kunkel321 and 172 guests