It is currently December 3rd, 2020, 10:35 am

[BUG?] Image Dimensions Not 0 For Non Existing Image

Report bugs with the Rainmeter application and suggest features.
User avatar
jsmorley
Developer
Posts: 21520
Joined: April 19th, 2009, 11:02 pm
Location: Fort Hunt, Virginia, USA

Re: [BUG?] Image Dimensions Not 0 For Non Existing Image

Post by jsmorley »

Yincognito wrote: November 15th, 2020, 4:59 am Nice one liner without the need for a batch file. :thumbup: I'll keep this in mind for the more general purpose of checking if a file of any type exists. Just for reference - I'm sure it's trivial, but how would a Lua script for this look like? It'll be faster than the RunCommand variant, right?
Much, much faster...

skin:

Code: Select all

[Rainmeter]
Update=1000
DynamicWindowSize=1
AccurateText=1

[Variables]

[Lua]
Measure=Script
ScriptFile=Test.lua
Disabled=1

[MeasureCheckFile]
Measure=Calc
Formula=[&Lua:exists('#@#Images\lampoon.jpg')]
DynamicVariables=1
IfCondition=MeasureCheckFile=1
IfTrueAction=[!SetOption MeterExists Text "lampoon.jpg FOUND!"][!UpdateMeter *][!Redraw]
IfFalseAction=[!SetOption MeterExists Text "lampoon.jpg NOT FOUND!"][!UpdateMeter *][!Redraw]

[MeterExists]
Meter=String
FontSize=15
FontWeight=400
FontColor=255,255,255,255
SolidColor=47,47,47,255
Padding=5,5,5,5
AntiAlias=1
Test.lua:

Code: Select all

function exists(fileArg)
   f=io.open(fileArg,'r')
   if f~=nil then io.close(f) return 1 else return -1 end
end
I did this with Inline Lua and a Calc measure to give me more flexibility on what file path\name I am looking for, as you can have as many of them as you want all accessing the same Lua measure and exists() function. I also want to be sure that I can easily change this so it isn't checking for the file on each and every skin update. I can add UpdateDivider or !Pause/!UnPause as needed on the Calc measure.

In the Lua, you are simply opening the file, which creates a "file handle". If the file handle is nil, which is Lua'ese for "doesn't exist", then return -1, else return 1. Note that ~= is how you say "not equal to" in Lua.
User avatar
Yincognito
Posts: 2934
Joined: February 27th, 2015, 2:38 pm
Location: Terra Yincognita

Re: [BUG?] Image Dimensions Not 0 For Non Existing Image

Post by Yincognito »

jsmorley wrote: November 15th, 2020, 12:14 pm Much, much faster...
Thanks. ;-)
User avatar
jsmorley
Developer
Posts: 21520
Joined: April 19th, 2009, 11:02 pm
Location: Fort Hunt, Virginia, USA

Re: [BUG?] Image Dimensions Not 0 For Non Existing Image

Post by jsmorley »

Yincognito wrote: November 15th, 2020, 12:26 pm Thanks. ;-)
Sure thing.

The big difference between doing this in Lua vs RunCommand is that the environment that this is run in, either the Lua interpreter or the cmd or PowerShell Windows shells, are handled differently. With Lua, it is set up and ready to go one time, when the skin is loaded or refreshed. With cmd or PowerShell, RunCommand has to "stand up" the environment each and every time, which is actually really slow.

Nothing about this function in Lua or more or less the same thing in cmd is appreciably different in performance. They are both going to be so fast they round to zero. The difference is that standing up the cmd shell or loading PowerShell takes some time. Probably a second or two. With Lua, you are going to see the result more or less instantaneously, during the first skin update.
User avatar
Yincognito
Posts: 2934
Joined: February 27th, 2015, 2:38 pm
Location: Terra Yincognita

Re: [BUG?] Image Dimensions Not 0 For Non Existing Image

Post by Yincognito »

jsmorley wrote: November 15th, 2020, 12:33 pm Sure thing.

The big difference between doing this in Lua vs RunCommand is that the environment that this is run in, either the Lua interpreter or the cmd or PowerShell Windows shells, are handled differently. With Lua, it is set up and ready to go one time, when the skin is loaded or refreshed. With cmd or PowerShell, RunCommand has to "stand up" the environment each and every time, which is actually really slow.

Nothing about this function in Lua or more or less the same thing in cmd is appreciably different in performance. They are both going to be so fast they round to zero. The difference is that standing up the cmd shell or loading PowerShell takes some time. Probably a second or two. With Lua, you are going to see the result more or less instantaneously, during the first skin update.
Agreed. For this reason such a case is a perfect example where Lua is indeed the way to go (and even more so if you need to check multiple files compared to just one). That being said, it's a bit strange that Rainmeter doesn't have a straight forward "native" way of doing the same thing - I'm not much of an expert, but from what I could read, using, say, FileView to do that (if possible) has the potential of being slower as well.
User avatar
jsmorley
Developer
Posts: 21520
Joined: April 19th, 2009, 11:02 pm
Location: Fort Hunt, Virginia, USA

Re: [BUG?] Image Dimensions Not 0 For Non Existing Image

Post by jsmorley »

If you want this to be more "interactive" and less "automatic", you might do something like this:

Code: Select all

[Rainmeter]
Update=1000
DynamicWindowSize=1
AccurateText=1

[Variables]

[Lua]
Measure=Script
ScriptFile=Test.lua
Paused=1
DynamicVariables=1
IfConditionMode=1
IfCondition=[&Lua:exists('#@#Images\#ImageName#')] = 1
IfTrueAction=[!SetOption MeterExists Text "#ImageName# FOUND!"][!UpdateMeter *][!Redraw]
IfFalseAction=[!SetOption MeterExists Text "#ImageName# NOT FOUND!"][!UpdateMeter *][!Redraw]

[MeterCheckLampoon]
Meter=String
FontSize=15
FontWeight=400
FontColor=255,255,255,255
SolidColor=47,47,47,255
Padding=5,5,5,5
AntiAlias=1
Text=Check lampoon.jpg
LeftMouseUpAction=[!SetVariable ImageName "lampoon.jpg"][!UnpauseMeasure Lua][!UpdateMeasure Lua][!PauseMeasure Lua]

[MeterCheckLaughing]
Meter=String
X=5R
FontSize=15
FontWeight=400
FontColor=255,255,255,255
SolidColor=47,47,47,255
Padding=5,5,5,5
AntiAlias=1
Text=Check laughing.jpg
LeftMouseUpAction=[!SetVariable ImageName "laughing.jpg"][!UnpauseMeasure Lua][!UpdateMeasure Lua][!PauseMeasure Lua]

[MeterExists]
Meter=String
Y=10R
FontSize=15
FontWeight=400
FontColor=255,255,255,255
SolidColor=47,47,47,255
Padding=5,5,5,5
AntiAlias=1
This will let you use the variable #ImageName# as a single general-purpose argument for the name to look for.
User avatar
Yincognito
Posts: 2934
Joined: February 27th, 2015, 2:38 pm
Location: Terra Yincognita

Re: [BUG?] Image Dimensions Not 0 For Non Existing Image

Post by Yincognito »

jsmorley wrote: November 17th, 2020, 1:40 pm If you want this to be more "interactive" and less "automatic", you might do something like this:
[...]
This will let you use the variable #ImageName# as a single general-purpose argument for the name to look for.
Thanks again. Out of curiosity, would you recommend using multiple such conditions in the native code that calls Lua, or within the Lua code itself? I'm referring to the efficiency of operations on multiple files, and also to the possibility that some conditions might "conflict" with one another (e.g. accessing the same file, etc).
User avatar
jsmorley
Developer
Posts: 21520
Joined: April 19th, 2009, 11:02 pm
Location: Fort Hunt, Virginia, USA

Re: [BUG?] Image Dimensions Not 0 For Non Existing Image

Post by jsmorley »

Yincognito wrote: November 17th, 2020, 4:03 pm Thanks again. Out of curiosity, would you recommend using multiple such conditions in the native code that calls Lua, or within the Lua code itself? I'm referring to the efficiency of operations on multiple files, and also to the possibility that some conditions might "conflict" with one another (e.g. accessing the same file, etc).
Well, how you approach this depends on the situation really. You could hard-code the file names into the Lua I guess, and maybe have a separate function() for each, but I don't really see any advantage. That last skin I posted shows how you can access any file name, and I don't see any possibility of conflict. Maybe I'm not understanding the question...
User avatar
Yincognito
Posts: 2934
Joined: February 27th, 2015, 2:38 pm
Location: Terra Yincognita

Re: [BUG?] Image Dimensions Not 0 For Non Existing Image

Post by Yincognito »

jsmorley wrote: November 17th, 2020, 4:12 pm Well, how you approach this depends on the situation really. You could hard-code the file names into the Lua I guess, and maybe have a separate function() for each, but I don't really see any advantage. That last skin I posted shows how you can access any file name, and I don't see any possibility of conflict. Maybe I'm not understanding the question...
No, I mean is doing:

Code: Select all

function exists(fileArg)
   f=io.open(fileArg,'r')
   if f~=nil then io.close(f) return 1 else return -1 end
end

Code: Select all

IfCondition=([&Lua:exists('#@#Images\#ImageName1#')]=1) && ([&Lua:exists('#@#Images\#ImageName2#')]=1)
going to be the same (in terms of file access and/or code efficiency) than:

Code: Select all

function exists(fileArg1,fileArg2)
   f1=io.open(fileArg1,'r')
   f2=io.open(fileArg2,'r')
   if (f1~=nil) and (f2~=nil) then io.close(f1) io.close(f2) return 1 else return -1 end
end

Code: Select all

IfCondition=([&Lua:exists('#@#Images\#ImageName1#','#@#Images\#ImageName2#')]=1)
(bear in mind I modified the Lua code on the fly, without really checking if the syntax is 100% correct)?

That, of course, if the Lua-Rainmeter combo accepts multiple arguments (I guess they can be merged into a string list, if not). Just curious if there's any advantage or difference between the 2 approaches above (i.e. code that handles multiple files in native code vs bare Lua).
User avatar
jsmorley
Developer
Posts: 21520
Joined: April 19th, 2009, 11:02 pm
Location: Fort Hunt, Virginia, USA

Re: [BUG?] Image Dimensions Not 0 For Non Existing Image

Post by jsmorley »

I doubt there is any significant difference in performance. I think I would lean toward:

IfCondition=([&Lua:exists('#@#Images\#ImageName1#')]=1) && ([&Lua:exists('#@#Images\#ImageName2#')]=1)

Since it centers the control in one place and is the most flexible. No "assumptions" are made...

There isn't going to be any performance enhancement just going out to the Lua one time with two parameters over going out twice with a single parameter. As I noted before, the Lua environment is already fully up and waiting for you as soon as you load the skin. Performance-wise, calling a Lua function is no more than it would be for a built-in measure in Rainmeter.

But yes, you can pass as many comma separated arguments to the Lua function as you like. Lua is pretty forgiving about mismatches on the number of arguments. If you define two and send only one, Lua won't care, the value for the second one will just be nil. if you define one and send two, Lua won't care, it will get the second one, but you will have to access it if desired by using a "table" arg[] that is automatically created of the arguments to a function. arg[1] is the first argument, arg[2] is the second, and so on.

However, with the way you wrote the Lua, you are locked into always sending two file arguments, or it will just always return -1.

A function in Lua will accept a variable number of arguments, just define it with a single argument of .... Then you can just see how many were sent to the current function with a built-in variable #arg, which is the "count" of the table arg[], and branch to different if statements based on that, but I doubt the complexity is going to be worth it.

This will certainly work ok...

Code: Select all

IfCondition=([&Lua:exists('#@#Images\#ImageName1#')]=1)
IfCondition=([&Lua:exists('#@#Images\#ImageName1#','#@#Images\#ImageName2#')]=1)

Code: Select all

function exists(...)
	if #arg == 1 then
		f=io.open(arg[1],"r")
		if f~=nil then io.close(f) return 1 else return -1 end
	elseif #arg == 2 then
		f1=io.open(arg[1],"r")
		f2=io.open(arg[2],"r")
		if f1~=nil and f2~=nil then io.close(f1) io.close(f2) return 1 else return -1 end  
	else
		print('Huh?')
		return -1
	end
end

User avatar
Yincognito
Posts: 2934
Joined: February 27th, 2015, 2:38 pm
Location: Terra Yincognita

Re: [BUG?] Image Dimensions Not 0 For Non Existing Image

Post by Yincognito »

jsmorley wrote: November 17th, 2020, 6:56 pm I doubt there is any significant difference in performance. I think I would lean toward:

IfCondition=([&Lua:exists('#@#Images\#ImageName1#')]=1) && ([&Lua:exists('#@#Images\#ImageName2#')]=1)

Since it centers the control in one place and is the most flexible. No "assumptions" are made...

There isn't going to be any performance enhancement just going out to the Lua one time with two parameters over going out twice with a single parameter. As I noted before, the Lua environment is already fully up and waiting for you as soon as you load the skin. Performance-wise, calling a Lua function is no more than it would be for a built-in measure in Rainmeter.

But yes, you can pass as many comma separated arguments to the Lua function as you like. Lua is pretty forgiving about mismatches on the number of arguments. If you define two and send only one, Lua won't care, the value for the second one will just be nil. if you define one and send two, Lua won't care, it will get the second one, but you will have to access it if desired by using a "table" arg[] that is automatically created of the arguments to a function. arg[1] is the first argument, arg[2] is the second, and so on.

However, with the way you wrote the Lua, you are locked into always sending two file arguments, or it will just always return -1.

A function in Lua will accept a variable number of arguments, just define it with a single argument of .... Then you can just see how many were sent to the current function with a built-in variable #arg, which is the "count" of the table arg[], and branch to different if statements based on that, but I doubt the complexity is going to be worth it.

This will certainly work ok...

Code: Select all

IfCondition=([&Lua:exists('#@#Images\#ImageName1#','#@#Images\#ImageName2#')]=1)

Code: Select all

function exists(...)
   if #arg == 1 then
		f=io.open(arg[1],"r")
		if f~=nil then io.close(f) return 1 else return -1 end
   elseif #arg == 2 then
		f1=io.open(arg[1],"r")
		f2=io.open(arg[2],"r")
		if f1~=nil and f2~=nil then io.close(f1) io.close(f2) return 1 else return -1 end   
   end
end
Ah, very interesting. I was aware of the argument flexibility is most programming languages (like defining two and send only one, e.g. the 2nd being optional), but defining one and send two and Lua being ok with it is new to me. It's interesting, and your example using ... is much appreciated. In the Lua code, if possible, I would rather lean into doing something like (again, just writing on the fly, have no idea if and how regular or array variables are "declared" in Lua):

Code: Select all

function exists(...)
   count=0
   for i=1 to #arg
     f[i]=io.open(arg[i],"r")
     if f[i]~=nil then io.close(f[i]) count=count+1 end
   next i
   if count==#arg then return 1 else return -1 end
end
to make the code suitable for any number of arguments, without having to write separate IFs for every possible number of arguments. Obviously, for OR logical operators this would have to be slightly modified, but for the AND scenario I think it would do (bar the possible mistakes I have in the code, of course).