GDI+ standard library 1.45 by tic

Post your working scripts, libraries and tools for AHK v1.1 and older
robodesign
Posts: 932
Joined: 30 Sep 2017, 03:59
Location: Romania
Contact:

Re: GDI+ standard library 1.45 by tic

28 Oct 2019, 13:02

Hello, guys!

I added 7 new functions to the GDI+ library and fixed some issues related to Gdip_CreateFontFamilyFromFile(). It was not freeing up resources.
Spoiler
I have nothing planned [to add] for the moment ;-) . ... only bug fixes if I find issues.

Download link: https://github.com/marius-sucan/AHK-GDIp-Library-Compilation

Best regards, Marius.
-------------------------
KeyPress OSD v4: GitHub or forum. (presentation video)
Quick Picto Viewer: GitHub or forum.
AHK GDI+ expanded / compilation library (on GitHub)
My home page.
malcev
Posts: 1769
Joined: 12 Aug 2014, 12:37

Re: GDI+ standard library 1.45 by tic

08 Nov 2019, 05:15

I suggest to change PrintWindow function - check version of windows and if it is >= 8.1 then add default flag 2.
It will give us opportunity to capture hardware accelerated windows.
https://github.com/tpn/winddk-8.1/blob/master/Include/um/WinUser.h#L4408
robodesign
Posts: 932
Joined: 30 Sep 2017, 03:59
Location: Romania
Contact:

Re: GDI+ standard library 1.45 by tic

08 Nov 2019, 06:04

@malcev : thank you .... how to nicely detect windows >= 8.1 ?
-------------------------
KeyPress OSD v4: GitHub or forum. (presentation video)
Quick Picto Viewer: GitHub or forum.
AHK GDI+ expanded / compilation library (on GitHub)
My home page.
malcev
Posts: 1769
Joined: 12 Aug 2014, 12:37

Re: GDI+ standard library 1.45 by tic

08 Nov 2019, 06:12

A_OSVersion?
robodesign
Posts: 932
Joined: 30 Sep 2017, 03:59
Location: Romania
Contact:

Re: GDI+ standard library 1.45 by tic

08 Nov 2019, 08:22

Okay, I'll do so in the next version. Soonish.
-------------------------
KeyPress OSD v4: GitHub or forum. (presentation video)
Quick Picto Viewer: GitHub or forum.
AHK GDI+ expanded / compilation library (on GitHub)
My home page.
User avatar
jeeswg
Posts: 6902
Joined: 19 Dec 2016, 01:58
Location: UK

Re: GDI+ standard library 1.45 by tic

08 Nov 2019, 09:20

A_OSVersion is a bit odd in AHK v1, it sometimes returns a string.

To reliably get a number (and not a string): the AHK source code uses RtlGetVersion (or if that's not available, GetVersionEx).
homepage | tutorials | wish list | fun threads | donate
WARNING: copy your posts/messages before hitting Submit as you may lose them due to CAPTCHA
guest3456
Posts: 3453
Joined: 09 Oct 2013, 10:31

Re: GDI+ standard library 1.45 by tic

26 Dec 2019, 17:55

do you guys think we should be looking up the DllCall addresses before hand? especially when doing pixelsearches or imagesearches with GDIP, it could be a noticeable difference

compare these two versions of the Gdip_SetPixel() func.. this benchmark was originally done by Rseding91 in the old forum. the speed increase is non-negligible

Code: Select all

#include Gdip_All.ahk
Setbatchlines -1
pToken := Gdip_Startup()
out := ""
Loop, 2
{
   ;thisfunc := Func("Gdip_SetPixel" . A_Index)
   thisfunc := "Gdip_SetPixel" . A_Index
   tooltip, testing %thisfunc%...
   out .= thisfunc " took " test(thisfunc) " ms`n"
}
tooltip,
msgbox, %out%
Gdip_Shutdown(pToken)
return


Gdip_SetPixel1(pBitmap, x, y, ARGB)
{
   return DllCall("gdiplus\GdipBitmapSetPixel", A_PtrSize ? "UPtr" : "UInt", pBitmap, "int", x, "int", y, "int", ARGB)
}

Gdip_SetPixel2(pBitmap, x, y, ARGB)
{
   ;// cant use static initializer becuase we have no module handle at loadtime.. we only have a module handle at runtime after doing LoadLibrary in Gdip_Startup
   static GdipBitmapSetPixelAddr
   if (!GdipBitmapSetPixelAddr)
      GdipBitmapSetPixelAddr := DllCall("GetProcAddress", "Ptr", DllCall("GetModuleHandle", "Str", "gdiplus", "Ptr"), "AStr", "GdipBitmapSetPixel", "Ptr")
   return DllCall(GdipBitmapSetPixelAddr, A_PtrSize ? "UPtr" : "UInt", pBitmap, "int", x, "int", y, "int", ARGB)
}


test(func)
{
   Width = 1280
   Height = 720
   pBitmap := Gdip_CreateBitmap(Width, Height)
   G := Gdip_GraphicsFromImage(pBitmap)
   start := A_TickCount
   Loop,%Width%
   {
      X := A_Index - 1
      Loop,%Height%
         %func%(pBitmap, X, A_Index-1, 0xFF0000FF)
   }
   end := A_TickCount - start
   Gdip_DisposeImage(pBitmap)
   Gdip_DeleteGraphics(G)
   return end
}


malcev
Posts: 1769
Joined: 12 Aug 2014, 12:37

Re: GDI+ standard library 1.45 by tic

26 Dec 2019, 18:16

Yes, and If You want speed, You do not have to use functions.
robodesign
Posts: 932
Joined: 30 Sep 2017, 03:59
Location: Romania
Contact:

Re: GDI+ standard library 1.45 by tic

27 Dec 2019, 17:37

Best is to use.... Bitmap lock bits. A lot more faster.
-------------------------
KeyPress OSD v4: GitHub or forum. (presentation video)
Quick Picto Viewer: GitHub or forum.
AHK GDI+ expanded / compilation library (on GitHub)
My home page.
guest3456
Posts: 3453
Joined: 09 Oct 2013, 10:31

Re: GDI+ standard library 1.45 by tic

29 Dec 2019, 13:31

we're not talking about whether lockbits is faster.. we're talking about the DllCall overhead

AHK_H has two features that are even faster... using its DynaCall() or using its winApi functions that are already built in:

Code: Select all

#include Gdip_All.ahk
Setbatchlines -1
pToken := Gdip_Startup()
out := ""
Loop, 4
{
   ; thisfunc := Func("Gdip_SetPixel" . A_Index)
   thisfunc := "Gdip_SetPixel" . A_Index
   tooltip, testing %thisfunc%...
   out .= thisfunc " took " test(thisfunc) " ms`n"
}
tooltip,
msgbox, %out%
Gdip_Shutdown(pToken)
return


Gdip_SetPixel1(pBitmap, x, y, ARGB)
{
   return DllCall("gdiplus\GdipBitmapSetPixel", A_PtrSize ? "UPtr" : "UInt", pBitmap, "int", x, "int", y, "int", ARGB)
}

Gdip_SetPixel2(pBitmap, x, y, ARGB)
{
   ;// cant use static initializer becuase we have no module handle at loadtime.. we only have a module handle at runtime after doing LoadLibrary in Gdip_Startup
   static GdipBitmapSetPixelAddr
   if (!GdipBitmapSetPixelAddr)
      GdipBitmapSetPixelAddr := DllCall("GetProcAddress"
                                             , "Ptr", DllCall("GetModuleHandle", "Str", "gdiplus", "Ptr")
                                             , "AStr", "GdipBitmapSetPixel"
                                             , "Ptr")
   return DllCall(GdipBitmapSetPixelAddr, A_PtrSize ? "UPtr" : "UInt", pBitmap, "int", x, "int", y, "int", ARGB)
}

Gdip_SetPixel3(pBitmap, x, y, ARGB)
{
   ;// AHK_H DynaCall()
   ;// https://hotkeyit.github.io/v2/docs/commands/DynaCall.htm
   static GdipBitmapSetPixelDyna := DynaCall("gdiplus\GdipBitmapSetPixel", "tiii")
   %GdipBitmapSetPixelDyna%(pBitmap, x, y, ARGB)
}

Gdip_SetPixel4(pBitmap, x, y, ARGB)
{
   ;// AHK_H built-in WinApi calls
   ;// https://hotkeyit.github.io/v2/docs/commands/WinApi.htm
   GdipBitmapSetPixel(pBitmap, x, y, ARGB)
}


test(func)
{
   Width = 1280
   Height = 720
   pBitmap := Gdip_CreateBitmap(Width, Height)
   G := Gdip_GraphicsFromImage(pBitmap)
   start := A_TickCount
   Loop,%Width%
   {
      X := A_Index - 1
      Loop,%Height%
         %func%(pBitmap, X, A_Index-1, 0xFF0000FF)
   }
   end := A_TickCount - start
   Gdip_DisposeImage(pBitmap)
   Gdip_DeleteGraphics(G)
   return end
}


malcev
Posts: 1769
Joined: 12 Aug 2014, 12:37

Re: GDI+ standard library 1.45 by tic

30 Dec 2019, 01:00

As I said before - if You want speed, do not use functions, do not use not needed expressions (A_PtrSize ? "UPtr" : "UInt"), place quotes around types and use ahk64bit
I do not have AHK_H, but on AHK_L 64bit it takes 5 seconds: on my PC.

Code: Select all

#include Gdip_All.ahk
Setbatchlines -1
pToken := Gdip_Startup()
out := ""
Loop, 2
{
   ;thisfunc := Func("Gdip_SetPixel" . A_Index)
   thisfunc := "Gdip_SetPixel" . A_Index
   tooltip, testing %thisfunc%...
   out .= thisfunc " took " test(thisfunc) " ms`n"
}
tooltip,
msgbox, %out%
Gdip_Shutdown(pToken)
return
#include Gdip_All.ahk

Gdip_SetPixel1(pBitmap, x, y, ARGB)
{
   return DllCall("gdiplus\GdipBitmapSetPixel", A_PtrSize ? "UPtr" : "UInt", pBitmap, "int", x, "int", y, "int", ARGB)
}

Gdip_SetPixel2(pBitmap, x, y, ARGB)
{
   ;// cant use static initializer becuase we have no module handle at loadtime.. we only have a module handle at runtime after doing LoadLibrary in Gdip_Startup
   static GdipBitmapSetPixelAddr
   if (!GdipBitmapSetPixelAddr)
      GdipBitmapSetPixelAddr := DllCall("GetProcAddress", "Ptr", DllCall("GetModuleHandle", "Str", "gdiplus", "Ptr"), "AStr", "GdipBitmapSetPixel", "Ptr")
   return DllCall(GdipBitmapSetPixelAddr, A_PtrSize ? "UPtr" : "UInt", pBitmap, "int", x, "int", y, "int", ARGB)
}


test(func)
{
   Width = 1280
   Height = 720
   pBitmap := Gdip_CreateBitmap(Width, Height)
   G := Gdip_GraphicsFromImage(pBitmap)
   GdipBitmapSetPixelAddr := DllCall("GetProcAddress", "Ptr", DllCall("GetModuleHandle", "Str", "gdiplus", "Ptr"), "AStr", "GdipBitmapSetPixel", "Ptr")
   start := A_TickCount
   loop 10
   {
      Loop,%Width%
      {
         X := A_Index - 1
         Loop,%Height%
            DllCall(GdipBitmapSetPixelAddr, "ptr", pBitmap, "int", x, "int", A_Index-1, "int", 0xFF0000FF)
      }
   }
   msgbox % A_TickCount - start


   end := A_TickCount - start
   Gdip_DisposeImage(pBitmap)
   Gdip_DeleteGraphics(G)
   return end
}
robodesign
Posts: 932
Joined: 30 Sep 2017, 03:59
Location: Romania
Contact:

Re: GDI+ standard library 1.45 by tic

11 Mar 2020, 15:07

Hello!

The extensive GDI+ library wrapper has been updated to v1.82 today: it brings several new functions, and bug fixes.

Gdip_AddPathRoundedRectangle()
Gdip_SetLinearGrBrushPresetBlend()
Gdip_GetRotatedEllipseDimensions()
Gdip_ErrrorHandler()
Gdip_GetImageThumbnail() [useless ^_^ ]

Link:
https://github.com/marius-sucan/AHK-GDIp-Library-Compilation

Best regards, Marius.
-------------------------
KeyPress OSD v4: GitHub or forum. (presentation video)
Quick Picto Viewer: GitHub or forum.
AHK GDI+ expanded / compilation library (on GitHub)
My home page.
User avatar
hoppfrosch
Posts: 443
Joined: 07 Oct 2013, 04:05
Location: Rhine-Maine-Area, Hesse, Germany
Contact:

Re: GDI+ standard library 1.45 by tic

12 Mar 2020, 02:05

You should note, which AHKV2 version your library is compatible with.
Just cloned your repo and tried to run the V2-Examples with a108 .... and it does not work ...

Anyway: Great work!
guest3456
Posts: 3453
Joined: 09 Oct 2013, 10:31

Re: GDI+ standard library 1.45 by tic

13 Mar 2020, 10:06

hoppfrosch wrote:
12 Mar 2020, 02:05
You should note, which AHKV2 version your library is compatible with.
Just cloned your repo and tried to run the V2-Examples with a108 .... and it does not work ...

Anyway: Great work!
his library doesn't guarantee to work with v2 so i dont know why he keeps that label. try this library, which his version is forked off of. it is meant for AHK v2:
https://github.com/mmikeww/AHKv2-Gdip

he keeps trying to merge in our changes, but he doesn't retain the commit and attribution history, and instead makes enormous commits where you cant track the changes. i have no idea why he decided to fork off another new library but then not even retain compatibility. i think he should have just proposed changes to the original repository and we could keep one main one.

robodesign
Posts: 932
Joined: 30 Sep 2017, 03:59
Location: Romania
Contact:

Re: GDI+ standard library 1.45 by tic

13 Mar 2020, 16:29

guest3456 wrote:
13 Mar 2020, 10:06
hoppfrosch wrote:
12 Mar 2020, 02:05
You should note, which AHKV2 version your library is compatible with.
Just cloned your repo and tried to run the V2-Examples with a108 .... and it does not work ...

Anyway: Great work!
his library doesn't guarantee to work with v2 so i dont know why he keeps that label. try this library, which his version is forked off of. it is meant for AHK v2:
https://github.com/mmikeww/AHKv2-Gdip

he keeps trying to merge in our changes, but he doesn't retain the commit and attribution history, and instead makes enormous commits where you cant track the changes. i have no idea why he decided to fork off another new library but then not even retain compatibility. i think he should have just proposed changes to the original repository and we could keep one main one.
Thank you hoppfrosch.

@ guest. Yes, I'm aware my GitHub "habits" are not pleasing for everyone, but I feel too lazy to make a commit for every change, small change. Besides, I'm constantly developing my image viewer /editor, and I test in stages the various functions I implement and come back to them to expand or fix them.

Regarding AHK v2. The same could have been said about mmikeww edition a few months ago. It no longer was working on the latest ahk v2 version, however he fixed it. Given the alpha version is not stabilized enough, I admit I neglect this considerably, as I wait for it to get closer to beta. I will fix my edition of the library to fully work with it but I'm in no hurry. I suppose there are not many users of ahk v2...

If there are here people who really want to use my library on v2, I can prioritize the work required for fixing it.

You said I don't retain compatibility. I do my best to keep my library easy to adopt. Simply by copy, paste. Does it break something? On AHK v1.1... It should be completely compatible... .

Best regards, Marius.
-------------------------
KeyPress OSD v4: GitHub or forum. (presentation video)
Quick Picto Viewer: GitHub or forum.
AHK GDI+ expanded / compilation library (on GitHub)
My home page.
guest3456
Posts: 3453
Joined: 09 Oct 2013, 10:31

Re: GDI+ standard library 1.45 by tic

13 Mar 2020, 17:59

robodesign wrote:
13 Mar 2020, 16:29
@ guest. Yes, I'm aware my GitHub "habits" are not pleasing for everyone, but I feel too lazy to make a commit for every change, small change. Besides, I'm constantly developing my image viewer /editor, and I test in stages the various functions I implement and come back to them to expand or fix them.
thats understandable. you can code however you want. its just bad practice to take other people's code, and not give them credit for it, when you can simply merge in commits that were authored by other people, and then if people visit your repo, they can easily see the commits that were created by others. and we could have all worked together to create one library instead. but i guess you wanted your own. thats allowed too

robodesign
Posts: 932
Joined: 30 Sep 2017, 03:59
Location: Romania
Contact:

Re: GDI+ standard library 1.45 by tic

14 Mar 2020, 02:52

It was not at all my intention to no longer give credits to people for their own work. Did you see that there's a specific read me file with a list of credits? Where the various functions come from, who wrote them. So, your assumption that I want to label everything as done by me is.... far from my intentions. and it is baseless, without proper arguments. However , I do apologize if this is how it feels for you.

I would actually like for us to merge our efforts into making a single gdip library wrapper edition. I just forked the repository, because I was not sure mmikeww would be open to my undertakings.

My only intention is to provide people interested with a closer to complete gdip library wrapper and to gather into it sparse contributions made by various people in seldom threads.

PS. For those eager to read credits... Here is the file containing credits/attributions:
https://github.com/marius-sucan/AHK-GDIp-Library-Compilation/blob/master/functions-list.txt

Best regards, Marius.
-------------------------
KeyPress OSD v4: GitHub or forum. (presentation video)
Quick Picto Viewer: GitHub or forum.
AHK GDI+ expanded / compilation library (on GitHub)
My home page.
R0nya
Posts: 6
Joined: 05 Aug 2016, 09:30

Re: GDI+ standard library 1.45 by tic

13 May 2020, 16:12

I can't find ImageSearch in that Compilation
robodesign
Posts: 932
Joined: 30 Sep 2017, 03:59
Location: Romania
Contact:

Re: GDI+ standard library 1.45 by tic

13 May 2020, 17:33

R0nya wrote:
13 May 2020, 16:12
I can't find ImageSearch in that Compilation
I found none to actually work. If you can point me to one I'll include it in the next planned release, which will come soon.

I also intend to separate it into two editions. One for ahk v1.1 and the other for v2.

Best regards, Marius.
-------------------------
KeyPress OSD v4: GitHub or forum. (presentation video)
Quick Picto Viewer: GitHub or forum.
AHK GDI+ expanded / compilation library (on GitHub)
My home page.
R0nya
Posts: 6
Joined: 05 Aug 2016, 09:30

Re: GDI+ standard library 1.45 by tic

17 May 2020, 17:37

This one works for me

Code: Select all

;**********************************************************************************
;
; Gdip_ImageSearch()
; by MasterFocus - 02/APRIL/2013 00:30h BRT
; Thanks to guest3456 for helping me ponder some ideas
; Requires GDIP, Gdip_SetBitmapTransColor() and Gdip_MultiLockedBitsSearch()
; http://www.autohotkey.com/board/topic/71100-gdip-imagesearch/
;
; Licensed under CC BY-SA 3.0 -> http://creativecommons.org/licenses/by-sa/3.0/
; I waive compliance with the "Share Alike" condition of the license EXCLUSIVELY
; for these users: tic , Rseding91 , guest3456
;
;==================================================================================
;
; This function searches for pBitmapNeedle within pBitmapHaystack
; The returned value is the number of instances found (negative = error)
;
; ++ PARAMETERS ++
;
; pBitmapHaystack and pBitmapNeedle
;   Self-explanatory bitmap pointers, are the only required parameters
;
; OutputList
;   ByRef variable to store the list of coordinates where a match was found
;
; OuterX1, OuterY1, OuterX2, OuterY2
;   Equivalent to ImageSearch's X1,Y1,X2,Y2
;   Default: 0 for all (which searches the whole haystack area)
;
; Variation
;   Just like ImageSearch, a value from 0 to 255
;   Default: 0
;
; Trans
;   Needle RGB transparent color, should be a numerical value from 0 to 0xFFFFFF
;   Default: blank (does not use transparency)
;
; SearchDirection
;   Haystack search direction
;     Vertical preference:
;       1 = top->left->right->bottom [default]
;       2 = bottom->left->right->top
;       3 = bottom->right->left->top
;       4 = top->right->left->bottom
;     Horizontal preference:
;       5 = left->top->bottom->right
;       6 = left->bottom->top->right
;       7 = right->bottom->top->left
;       8 = right->top->bottom->left
;
; Instances
;   Maximum number of instances to find when searching (0 = find all)
;   Default: 1 (stops after one match is found)
;
; LineDelim and CoordDelim
;   Outer and inner delimiters for the list of coordinates (OutputList)
;   Defaults: "`n" and ","
;
; ++ RETURN VALUES ++
;
; -1001 ==> invalid haystack and/or needle bitmap pointer
; -1002 ==> invalid variation value
; -1003 ==> X1 and Y1 cannot be negative
; -1004 ==> unable to lock haystack bitmap bits
; -1005 ==> unable to lock needle bitmap bits
; any non-negative value ==> the number of instances found
;
;==================================================================================
;
;**********************************************************************************

Gdip_ImageSearch(pBitmapHaystack,pBitmapNeedle,ByRef OutputList=""
,OuterX1=0,OuterY1=0,OuterX2=0,OuterY2=0,Variation=0,Trans=""
,SearchDirection=1,Instances=1,LineDelim="`n",CoordDelim=",") {

    ; Some validations that can be done before proceeding any further
    If !( pBitmapHaystack && pBitmapNeedle )
        Return -1001
    If Variation not between 0 and 255
        return -1002
    If ( ( OuterX1 < 0 ) || ( OuterY1 < 0 ) )
        return -1003
    If SearchDirection not between 1 and 8
        SearchDirection := 1
    If ( Instances < 0 )
        Instances := 0

    ; Getting the dimensions and locking the bits [haystack]
    Gdip_GetImageDimensions(pBitmapHaystack,hWidth,hHeight)
    ; Last parameter being 1 says the LockMode flag is "READ only"
    If Gdip_LockBits(pBitmapHaystack,0,0,hWidth,hHeight,hStride,hScan,hBitmapData,1)
    OR !(hWidth := NumGet(hBitmapData,0,"UInt"))
    OR !(hHeight := NumGet(hBitmapData,4,"UInt"))
        Return -1004

    ; Careful! From this point on, we must do the following before returning:
    ; - unlock haystack bits

    ; Getting the dimensions and locking the bits [needle]
    Gdip_GetImageDimensions(pBitmapNeedle,nWidth,nHeight)
    ; If Trans is correctly specified, create a backup of the original needle bitmap
    ; and modify the current one, setting the desired color as transparent.
    ; Also, since a copy is created, we must remember to dispose the new bitmap later.
    ; This whole thing has to be done before locking the bits.
    If Trans between 0 and 0xFFFFFF
    {
        pOriginalBmpNeedle := pBitmapNeedle
        pBitmapNeedle := Gdip_CloneBitmapArea(pOriginalBmpNeedle,0,0,nWidth,nHeight)
        Gdip_SetBitmapTransColor(pBitmapNeedle,Trans)
        DumpCurrentNeedle := true
    }

    ; Careful! From this point on, we must do the following before returning:
    ; - unlock haystack bits
    ; - dispose current needle bitmap (if necessary)

    If Gdip_LockBits(pBitmapNeedle,0,0,nWidth,nHeight,nStride,nScan,nBitmapData)
    OR !(nWidth := NumGet(nBitmapData,0,"UInt"))
    OR !(nHeight := NumGet(nBitmapData,4,"UInt"))
    {
        If ( DumpCurrentNeedle )
            Gdip_DisposeImage(pBitmapNeedle)
        Gdip_UnlockBits(pBitmapHaystack,hBitmapData)
        Return -1005
    }
    
    ; Careful! From this point on, we must do the following before returning:
    ; - unlock haystack bits
    ; - unlock needle bits
    ; - dispose current needle bitmap (if necessary)

    ; Adjust the search box. "OuterX2,OuterY2" will be the last pixel evaluated
    ; as possibly matching with the needle's first pixel. So, we must avoid going
    ; beyond this maximum final coordinate.
    OuterX2 := ( !OuterX2 ? hWidth-nWidth+1 : OuterX2-nWidth+1 )
    OuterY2 := ( !OuterY2 ? hHeight-nHeight+1 : OuterY2-nHeight+1 )

    OutputCount := Gdip_MultiLockedBitsSearch(hStride,hScan,hWidth,hHeight
    ,nStride,nScan,nWidth,nHeight,OutputList,OuterX1,OuterY1,OuterX2,OuterY2
    ,Variation,SearchDirection,Instances,LineDelim,CoordDelim)

    Gdip_UnlockBits(pBitmapHaystack,hBitmapData)
    Gdip_UnlockBits(pBitmapNeedle,nBitmapData)
    If ( DumpCurrentNeedle )
        Gdip_DisposeImage(pBitmapNeedle)

    Return OutputCount
}

;///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
;///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
;///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
Last edited by BoBo on 04 Jun 2020, 00:27, edited 1 time in total.
Reason: Fixed broken link within code box

Return to “Scripts and Functions (v1)”

Who is online

Users browsing this forum: No registered users and 72 guests