Basic Image Editor Class

Post your working scripts, libraries and tools for AHK v1.1 and older
User avatar
maestrith
Posts: 825
Joined: 16 Oct 2013, 13:52

Basic Image Editor Class

07 Jan 2020, 09:03

This was written for another project and I thought that someone could possibly use it.

Code: Select all

; All WIA_ Methods are from https://www.autohotkey.com/boards/viewtopic.php?t=7254
; Press Up/Down/Left/Right optionally with either Shift, Control, or Control+Shift to move the Crop window
#SingleInstance,Force
BIE:=New BasicImageEdit(800,600,{Margin:[0,0],Title:"Basic Image Editor",Before:{Item:{x:"m",y:"m",Type:"Edit",w:200}}})
BIE.Exit:=1						;If you are not using this as a part of a larger project it will ExitApp when you hit escape or close the window
BIE.SaveFile:=A_ScriptDir "\temp.jpg"	;Default Save File Location (Will not ask where to save if it is set)
BIE.SaveWidth:=500					;Default Maximum Save Width
BIE.SaveHeight:=500					;Default Maximum Save Height
BIE.Crop()						;Display the Crop window
ControlFocus,,% BIE.ID.Item
return
Class BasicImageEdit{
	static Keep:=[]
	__New(W:=400,H:=400,Extra:=""){
		Gui,Resize:Destroy
		Gui,Resize:Default
		Gui,Color,0,0
		Gui,Font,c0xAAAAAA
		if(Extra.Margin.1!="")
			Gui,Margin,% Extra.Margin.1,% Extra.Margin.2
		Extra.Title:=Extra.Title?Extra.Title:"Basic Image Editor",this.Controls:=[],this.ID:=[]
		for a,b in Extra.Before{
			Pos:=""
			for c,d in ["x","y","w","h"]
				if((Val:=b[d])!="")
					Pos.=d Val " "
			Gui,Add,% b.Type,% Pos "HWNDHWND"
			this.Controls[a]:=HWND,this.ID[a]:="ahk_id" HWND
		}
		Gui,+HWNDMain +Resize +LabelBasicImageEdit.
		Gui,Add,Text,w%W% h%H% HWNDPic +0xE
		for a,b in {Border:33,Caption:4}
			this[a]:=DllCall("GetSystemMetrics",UInt,b)
		SetWinDelay,-1
		Gui,Add,Button,HWNDOpen,&Open
		Gui,Add,Button,x+m HWNDCrop Default,Cro&p
		Gui,Add,Button,x+m HWNDSave,&Save
		Gui,Add,Button,x+m HWNDRotate,&Rotate
		for a,b in {Open:[Open,this.Open.Bind(this)],Crop:[Crop,(BoundCrop:=this.Crop.Bind(this))],Save:[Save,this.Save.Bind(this)],Rotate:[Rotate,this.Rotate.Bind(this)]}{
			this.AllCtrl[a]:={HWND:b.1,Bound:b.2},Bound:=b.2
			GuiControl,+g,% b.1,%Bound%
		}this.DetectHiddenWindows:=A_DetectHiddenWindows
		DetectHiddenWindows,On
		ControlGetPos,x,y,w,h,,ahk_id%Pic%
		this.PicStart:=y-this.Border-this.Caption
		Gui,Show,,% Extra.Title
		Gui,Crop:Destroy
		Gui,Crop:Default
		Gui,+HWNDCrop +Owner%Main% +LabelBasicImageEdit. +Resize +ToolWindow
		this.MoveBound:=this.EnterSizeMove.Bind(this),this.MoveExitBound:=this.ExitSizeMove.Bind(this),this.CropID:="ahk_id" Crop,this.CropHWND:=Crop,BasicImageEdit.Keep:=this,Adjust:=this.Adjust.Bind(this),this.IP:=ComObjCreate("WIA.ImageProcess"),this.RedrawBound:=this.Redraw.Bind(this),this.SWidth:=W,this.SHeight:=H,this.PicID:="ahk_id" Pic,this.PicHWND:=Pic,this.W:=W,this.H:=H,this.MainHWND:=Main,this.MainID:="ahk_id" Main,this.WinDelay:=A_WinDelay,OnMessage(0x231,this.MoveBound,-1),OnMessage(0x232,this.MoveExitBound,-1)
		Hotkey,IfWinActive,% this.CropID
		for a,b in ["Up","Down","Left","Right"]
			for c,d in ["","+","^+","^"]
				Hotkey,% d b,%Adjust%,On
		for a,b in {Enter:BoundCrop,"^a":this.SelectAll.Bind(this)}
			Hotkey,%a%,%b%,On
		ControlFocus,Button2,% this.MainID
	}Adjust(){
		Key:=RegExReplace(A_ThisHotkey,"\W"),Pos:=this.WinPos(this.CropHWND),Adjust:=GetKeyState("CTRL","P")?20:1,Shift:=GetKeyState("Shift","P")
		if(!Shift)
			(Key="Left")?Pos.X-=Adjust:Key="Right"?Pos.X+=Adjust:Key="Down"?Pos.Y+=Adjust:Key="Up"?Pos.Y-=Adjust:""
		else if(Shift)
			(Key="Left")?Pos.W-=Adjust:Key="Right"?Pos.W+=Adjust:Key="Up"?Pos.H-=Adjust:Key="Down"?Pos.H+=Adjust:""
		this.WinMove(this.CropID,Pos.X,Pos.Y,Pos.W+this.Border*2,Pos.H+this.Border*2+this.Caption),this.ExitSizeMove(0,0,0,this.CropHWND)
	}Base64(Format:="jpg"){
		this.WIA_ConvertImage(Format,,,1),(this.SaveWidth)?this.Resize(this.SaveWidth,this.SaveHeight,1,1):"",ARGB:=this.TempImg.FileData,Bytes:=ARGB.Count(),Bin:=ARGB.BinaryData,CP:=0,PTR:=NumGet(ComObjValue(Bin)+8+A_PtrSize),DllCall("Crypt32.dll\CryptBinaryToString","ptr",Ptr,"uint",Bytes,"uint",0x40000001,"ptr",0,"uint*",CP),VarSetCapacity(Str,CP*(A_IsUnicode?2:1)),DllCall("Crypt32.dll\CryptBinaryToString","ptr",Ptr,"uint",Bytes,"uint",0x40000001,"str",Str,"uint*",CP)
		return Str
	}Close(){
		HWND:=this,(HWND=(this:=BasicImageEdit.Keep).CropHWND)?this.CropVis:=0:""
		if(A_Gui="Resize")
			this.ExitApp()
	}Crop(){
		if(!this.Img.Width)
			return
		if(A_DetectHiddenWindows="Off")
			DetectHiddenWindows,On
		WinGet,Style,Style,% this.CropID
		if(Style&0x10000000=0){
			if(!this.Init)
				this.Init:=1,this.SelectAll()
			this.WinShow(this.CropID),this.CropVis:=1
		}else if(Style)
			this.Hide(this.CropID),ScaleW:=this.SWidth/this.OWidth,ScaleH:=this.SHeight/this.OHeight,this.CropVis:=0,Pic:=this.WinPos(this.PicHWND),Crop:=this.WinPos(this.CropHWND),Right:=((Pic.X+Pic.W)-(Crop.X+Crop.W+this.Border))//ScaleW,Bottom:=((Pic.Y+Pic.H)-(Crop.Y+Crop.H+this.Border+this.Caption))//ScaleH,Left:=((Crop.X+this.Border)-Pic.X)//ScaleW,Top:=((Crop.Y+this.Border+this.Caption)-Pic.Y)//ScaleH,this.WIA_CropImage(Left,Top,Right,Bottom),this.WIA_ScaleImage(this.W,this.H),this.DisplayImage()
	}DisplayImage(){
		PicObj:=this.WIA_GetImageBitmap(this.Scaled),HBM:=PicObj.Handle
		for a,b in {OWidth:this.Img.Width,OHeight:this.Img.Height,SWidth:this.Scaled.Width,SHeight:this.Scaled.Height}
			this[a]:=b
		SendMessage,(STM_SETIMAGE:=0x172),(IMAGE_BITMAP:=0x0),%HBM%,,% this.PicID
	}EnterSizeMove(a,b,c,d){
		if(d=this.MainHWND)
			Pic:=this.WinPos(this.PicHWND),Crop:=this.WinPos(this.CropHWND),this.Hide(this.CropID),this.Offset:={X:Pic.X-Crop.X,Y:Pic.Y-Crop.Y}
		return 0 ;Needed :)
	}Escape(a*){
		this:=BasicImageEdit.Keep
		if(A_Gui="Crop")
			this.Hide(this.CropID),this.CropVis:=0
		else if(A_Gui="Resize")
			this.ExitApp()
	}ExitApp(){
		if(this.Exit)
			ExitApp
		OnMessage(0x231,this.MoveBound,0)
		DetectHiddenWindows,% this.DetectHiddenWindows
		SetWinDelay,% this.WinDelay
		Gui,Resize:Destroy
	}ExitSizeMove(a,b,c,d){
		if(d=this.MainHWND){
			if(this.CropVis)
				Pic:=this.WinPos(this.PicHWND),this.WinMove(this.CropID,Pic.X-this.Offset.X,Pic.Y-this.Offset.Y),this.WinShow(this.CropID)
			this.Redraw()
		}else if(d=this.CropHWND)
			this.FixCrop()
		return 0 ;Needed :)
	}FixCrop(){
		Obj:=this.WinPos(this.CropHWND),Obj1:=this.WinPos(this.PicHWND),X:=Obj1.X-this.Border,Y:=Obj1.Y-(this.Border+this.Caption),NewX:=Obj.X<X?X:Obj.X,NewY:=Obj.Y<Y?Y:Obj.Y
		if(Obj.X+this.Border*2>(MaxX:=Obj1.X+Obj1.W))
			NewX:=MaxX-Obj.W-this.Border
		if(Obj.Y+this.Border*2+this.Caption>(MaxY:=Obj1.Y+Obj1.H))
			NewY:=MaxY-Obj.H-this.Border-this.Caption
		NewW:=NewX+Obj.W+this.Border>Obj1.X+Obj1.W?Obj1.W-(NewX-Obj1.X)+this.Border:Obj.W+this.Border*2
		if(NewW<40)
			NewW:=40,NewX:=Obj1.X+Obj1.W-40 ;-this.Border
		NewH:=NewY+Obj.H+this.Caption+this.Border>Obj1.Y+Obj1.H?Obj1.H-((NewY-Obj1.Y)+this.Border*2-this.Caption-1):Obj.H+this.Border*2+this.Caption
		this.WinMove(this.CropID,NewX,NewY,NewW,NewH)
	}Hide(ID){
		WinHide,%ID%
	}Open(File:=""){
		if(!FileExist(File))
			FileSelectFile,File,,,Image,*.png;*.jpg;*.bmp;*.tiff
		if(!FileExist(File))
			return
		this.Init:=0,this.OFile:=File,this.WIA_LoadImage(File),this.WIA_ScaleImage(this.W,this.H),this.DisplayImage()
	}Redraw(){
		this.WIA_ScaleImage(this.W,this.H),this.DisplayImage(),this.FixCrop()
	}Resize(Width,Height,Ratio:=1,TempImg:=0){
		this.WIA_ImageProcess(),this.IP.Filters.Add(this.IP.FilterInfos("Scale").FilterID),this.IP.Filters[1].Properties("MaximumWidth"):=Width,this.IP.Filters[1].Properties("MaximumHeight"):=Height,this.IP.Filters[1].Properties("PreserveAspectRatio"):=Ratio,TempImg?this.TempImg:=this.IP.Apply(this.TempImg):this.Img:=this.IP.Apply(this.Img)
	}Rotate(){
		this.WIA_ImageProcess(),this.IP.Filters.Add(this.IP.FilterInfos("RotateFlip").FilterID),this.IP.Filters[1].Properties("RotationAngle"):=90,this.Img:=this.IP.Apply(this.Img),this.WIA_ScaleImage(this.W,this.H),this.DisplayImage()
	}Save(){
		if(!File:=this.SaveFile)
			FileSelectFile,File,S16,,Save Cropped As,*.jpg;*.png;*.bmp;*.tiff;*.gif
		if(ErrorLevel)
			return
		if(!Ext:=this.SplitPath(File).Ext)
			File.=!Ext?"." this.SplitPath(this.OFile).Ext:"",Ext:=OExt
		if(this.Img.FileExtension!=Ext)
			this.WIA_ConvertImage(Ext)
		if(this.SaveWidth)
			this.Resize(this.SaveWidth,this.SaveHeight)
		if(FileExist(File))
			FileDelete,%File%
		this.Img.SaveFile(File)
	}SelectAll(){
		Pic:=this.WinPos(this.PicHWND),this.WinMove(this.CropID,Pic.X-this.Border,Pic.Y-this.Border-this.Caption,Pic.W+this.Border*2,Pic.H+(this.Border*2+this.Caption))
	}Size(Action,W,H){
		static Last:=[]
		HWND:=this,this:=BasicImageEdit.Keep
		if(HWND=this.MainHWND){
			GuiControl,MoveDraw,% this.PicHWND,% "h" (NewH:=H-35-this.PicStart) " w" (NewW:=W-20)
			for a,b in this.AllCtrl
				GuiControl,MoveDraw,% b.HWND,% "y" H-27
			this.W:=NewW,this.H:=NewH
		}else if(HWND=this.CropHWND||Action="Startup"){
			Width:=W+this.Border*2,Height:=H+this.Border+this.Caption+this.Border,Left:=this.Border,Right:=Width-this.Border,Bottom:=Height-this.Border,Top:=this.Caption+this.Border
			WinSet,Region,0-0 0-%Height% %Width%-%Height% %Width%-0 0-0 %Left%-%Top% %Right%-%Top% %Right%-%Bottom% %Left%-%Bottom% %Left%-%Top%,% this.CropID
		}if(Last.W!=W||Last.H!=H),Last.W:=W,Last.H:=H
			if(Redraw:=this.RedrawBound)
				SetTimer,%Redraw%,-200
	}Sleep(Sleep){
		Sleep,%Sleep%
	}SplitPath(Text){
		SplitPath,Text,File,Dir,Ext,NNE,Drive
		return {Text:Text,File:File,Dir:Dir,Ext:Ext,NNE:NNE,Drive:Drive}
	}WIA_ConvertImage(NewFormat,Quality:=100,Compression:="LZW",TempImg:="") {
		static FormatID:={BMP:"{B96B3CAB-0728-11D3-9D7B-0000F81EF32E}",JPG:"{B96B3CAE-0728-11D3-9D7B-0000F81EF32E}",GIF:"{B96B3CB0-0728-11D3-9D7B-0000F81EF32E}",PNG:"{B96B3CAF-0728-11D3-9D7B-0000F81EF32E}",TIFF:"{B96B3CB1-0728-11D3-9D7B-0000F81EF32E}"},Comp:={CCITT3:1,CCITT4:1,LZW:1,RLE:1,Uncompressed:1}
		if Quality Not Between 1 And 100
			return 0
		if(Comp[Compression]="")
			return 0
		if(!NewFormat:=FormatID[NewFormat])
			return
		this.WIA_ImageProcess(),this.IP.Filters.Add(this.IP.FilterInfos("Convert").FilterID),this.IP.Filters[1].Properties("FormatID"):=NewFormat,this.IP.Filters[1].Properties("Quality"):=Quality,this.IP.Filters[1].Properties("Compression"):=Compression,TempImg?this.TempImg:=this.IP.Apply(this.Img):this.Img:=this.IP.Apply(this.Img)
	}WIA_CropImage(Left,Top,Right,Bottom){
		this.WIA_ImageProcess(),this.IP.Filters.Add(this.IP.FilterInfos("Crop").FilterID),this.IP.Filters[1].Properties("Left"):=Left,this.IP.Filters[1].Properties("Top"):=Top,this.IP.Filters[1].Properties("Right"):=Right,this.IP.Filters[1].Properties("Bottom"):=Bottom,this.Img:=this.IP.Apply(this.Img)
	}WIA_GetImageBitmap(ImgObj) {
		return ImgObj.Filedata.Picture
	}WIA_ImageProcess() {
		while(this.IP.Filters.Count)
			this.IP.Filters.Remove(1)
	}WIA_LoadImage(ImgPath){
		this.Img:=ComObjCreate("WIA.ImageFile"),ComObjError(0),this.Img.LoadFile(ImgPath),ComObjError(1)
	}WIA_ScaleImage(PxWidth,PxHeight,KeepRatio:=1){
		if(this.Img.Width)
			this.WIA_ImageProcess(),this.IP.Filters.Add(this.IP.FilterInfos("Scale").FilterID),this.IP.Filters[1].Properties("MaximumWidth"):=PxWidth>0?PxWidth:PxHeight,this.IP.Filters[1].Properties("MaximumHeight"):=PxHeight>0?PxHeight:PxWidth,this.IP.Filters[1].Properties("PreserveAspectRatio"):=KeepRatio,this.Scaled:=this.IP.Apply(this.Img)
	}WinMove(Title,X,Y,W:="",H:=""){
		WinMove,%Title%,,%X%,%Y%,%W%,%H%
	}WinPos(HWND){
		VarSetCapacity(Rect,16),DllCall("GetClientRect",PTR,HWND,PTR,&Rect)
		WinGetPos,x,y,,,% "ahk_id" HWND
		return {x:x,y:y,w:(w:=NumGet(Rect,8)),h:(h:=NumGet(Rect,12)),text:"x" x " y" y " w" w " h" h}
	}WinShow(ID){
		WinShow,%ID%
	}
}
Added: Base64 Method to get the Base64 of the image
John H Wilson III 05/29/51 - 03/01/2020. You will be missed.AHK Studio OSDGUI Creator
Donations
Discord
All code is done on a 64 bit Windows 10 PC Running AutoHotkey x32

Return to “Scripts and Functions (v1)”

Who is online

Users browsing this forum: No registered users and 188 guests