Log in

View Full Version : Thumbnail preview script


2E7AH
20th December 2009, 03:12
I was making thumbnail preview with MPC and didn't liked the chosen thumbs, and as I can't change which thumbnails are chosen in MPC I started making AVS script
This is my first script (meaning not just two lines of text), so I guess AviSynth user will have suggestions which I would like to hear

I missed FOR ... loop a lot :)

Here is the script:
# only value that should be changed is file path (and logo perhaps), but also number of thumbnails,
# background resolution etc. can be changed (all values are automatically calculated)

file = "E:\Appleseed.Ex_Machina.2007.720p.BluRay.DualAudio_AC3_AAC.x264.mkv"

logo = "avisynth.png" # place in script folder
shadow = "shadow.png"

thumbs = 16 # max 25, but can be freely extended by replicating last lines
show_time = true # if set to "true", frames will have time as caption instead frame number
cover = true # display cover.jpg (or cover_name value) which should be in source file folder or specified in cover_name as full path
cover_name = "cover.jpg"
end_credits = false # set to "true" to reasonably try to avoid start/end credits

bg_width = 1200
bg_color = $F5F8FA
font = "Thebuchet MS"
shadow_opacity = 160
text_color = $000000
halo_color = $FFFFFF
size = 14
pad = 8

shuffle = 0 # shuffles frame matching

# below code shouldn't be changed, unless...

src = DirectShowSource(file, audio=false).ConvertToYUY2.ConvertToRGB
img = ImageSource(logo, pixel_type="rgb32")

rows = ceil(sqrt(thumbs))
columns = ceil(float(thumbs)/rows)
c_pad = 0

r_width = round(bg_width/columns) - pad
r_height = r_width * height(src)/width(src)
bg_height = (r_height + pad) * rows + height(ImageSource(logo))
frames = floor(FrameCount(src)/thumbs)
drop = Exist(shadow) ? ImageSource(shadow, pixel_type="rgb32").LanczosResize(r_width, r_height) : BlankClip

# functions

function c_time(clip src, int frame) {
hours = floor(frame/FrameRate(src)/3600)
minutes = floor(frame/FrameRate(src)/60) - hours*60
seconds = frame/FrameRate(src) - floor(frame/FrameRate(src)/60)*60
return string(hours, "%02.0f") + ":" + String(minutes, "%02.0f") + ":" + string(seconds, "%02.3f")
}

function frame(clip src, int r_width, int r_height, int frames, int shuffle, bool end_credits, bool show_time, int thumbs, int x){
y = end_credits == true && (x == 1 || x == thumbs) ? sign(x-1) : .5

Trim(src, x*frames - round(frames*y) - rand(shuffle), 0).LanczosResize(r_width, r_height)

show_time == true ? \
ShowTime(offset_f = x*frames - round(frames*y) - rand(shuffle), x = 45, y = r_height, \
font= "Lucida Console", size = 10, text_color = $FFFFFF, halo_color = $000000) \
: \
ShowFrameNumber(scroll = true, offset = x*frames - round(frames*y) - rand(shuffle), x = 8, y = r_height, \
font= "Lucida Console", size = 10, text_color = $FFFFFF, halo_color = $000000)
}

function x_pos(int r_width, int pad, int columns, int x) {
round(pad/2) + ((x-1)-floor((x-1)/columns)*columns)*(r_width + pad)-1
}

function y_pos(val logo, int r_height, int pad, int columns, int x) {
floor((x-1)/columns) * (r_height + pad) + round(pad/2) + height(ImageSource(logo))
}

function line(x) { (x - 1) * 15 - 3 }

# display

BlankClip(src, width=bg_width, height=bg_height, color=bg_color)

# info subtitles

filename = string(RightStr(file, Findstr(RevStr(file), "\") - 1))
resolution = "Resolution: " + string(Width(src)) + ":" + string(Height(src))
rate = "Frame Rate: " + string(FrameRate (src), "%.3f")
c_name = (FindStr(cover_name,"\") == 0) ? LeftStr(file, StrLen(file) - StrLen(filename)) + cover_name : cover_name

cover == true ? Eval("""
try { c_pad = width(ImageSource(c_name))*height(ImageSource(logo))/height(ImageSource(c_name)) }
catch(err_msg) { }
c_pad != 0 ? Layer(ImageSource(c_name).ConvertToRGB32.LanczosResize(c_pad, height(ImageSource(logo))), "add", 256, pad/2): NOP """) : NOP

height(ImageSource(logo)) > 25 ? Eval("""
Subtitle("Filename: " + filename, c_pad + pad, line(1) + 8, 0, FrameCount(src), \
font, 20, text_color, halo_color, spc = 6)
nl = 3""") : NOP
height(ImageSource(logo)) > 55 ? Eval("""
Subtitle(resolution, c_pad + pad, line(nl), 0, FrameCount(src), \
font, size, text_color, halo_color, spc = 6)
nl = 4""") : NOP
height(ImageSource(logo)) > 70 ? Eval("""
Subtitle(rate, c_pad + pad, line(nl), 0, FrameCount(src), \
font, size, text_color, halo_color, spc = 6)
nl = 5""") : NOP
height(ImageSource(logo)) > 40 ? Eval("""
Subtitle("Length: " + c_time(src, FrameCount(src)), c_pad + pad, line(nl), 0, FrameCount(src), \
font, size, text_color, halo_color, spc = 6)""") : NOP

Layer(img, "add", 224, x=bg_width-width(ImageSource(logo))-pad/2, y=2)

# thumbs
1 <= frames ? Eval("""
Layer(frame(src,r_width,r_height,frames,shuffle,end_credits,show_time,thumbs,1),"add",256,x_pos(r_width,pad,columns,1),y_pos(logo, r_height,pad,columns,1))
Layer(drop, "add", shadow_opacity, x=x_pos(r_width,pad,columns,1) + 6, y=y_pos(logo, r_height,pad,columns,1) + 3)""") : NOP
2 <= frames ? Eval("""
Layer(frame(src,r_width,r_height,frames,shuffle,end_credits,show_time,thumbs,2),"add",256,x_pos(r_width,pad,columns,2),y_pos(logo, r_height,pad,columns,2))
Layer(drop, "add", shadow_opacity, x=x_pos(r_width,pad,columns,2) + 6, y=y_pos(logo, r_height,pad,columns,2) + 3)""") : NOP
3 <= frames ? Eval("""
Layer(frame(src,r_width,r_height,frames,shuffle,end_credits,show_time,thumbs,3),"add",256,x_pos(r_width,pad,columns,3),y_pos(logo, r_height,pad,columns,3))
Layer(drop, "add", shadow_opacity, x=x_pos(r_width,pad,columns,3) + 6, y=y_pos(logo, r_height,pad,columns,3) + 3)""") : NOP
4 <= frames ? Eval("""
Layer(frame(src,r_width,r_height,frames,shuffle,end_credits,show_time,thumbs,4),"add",256,x_pos(r_width,pad,columns,4),y_pos(logo, r_height,pad,columns,4))
Layer(drop, "add", shadow_opacity, x=x_pos(r_width,pad,columns,4) + 6, y=y_pos(logo, r_height,pad,columns,4) + 3)""") : NOP
5 <= frames ? Eval("""
Layer(frame(src,r_width,r_height,frames,shuffle,end_credits,show_time,thumbs,5),"add",256,x_pos(r_width,pad,columns,5),y_pos(logo, r_height,pad,columns,5))
Layer(drop, "add", shadow_opacity, x=x_pos(r_width,pad,columns,5) + 6, y=y_pos(logo, r_height,pad,columns,5) + 3)""") : NOP
6 <= frames ? Eval("""
Layer(frame(src,r_width,r_height,frames,shuffle,end_credits,show_time,thumbs,6),"add",256,x_pos(r_width,pad,columns,6),y_pos(logo, r_height,pad,columns,6))
Layer(drop, "add", shadow_opacity, x=x_pos(r_width,pad,columns,6) + 6, y=y_pos(logo, r_height,pad,columns,6) + 3)""") : NOP
7 <= frames ? Eval("""
Layer(frame(src,r_width,r_height,frames,shuffle,end_credits,show_time,thumbs,7),"add",256,x_pos(r_width,pad,columns,7),y_pos(logo, r_height,pad,columns,7))
Layer(drop, "add", shadow_opacity, x=x_pos(r_width,pad,columns,7) + 6, y=y_pos(logo, r_height,pad,columns,7) + 3)""") : NOP
8 <= frames ? Eval("""
Layer(frame(src,r_width,r_height,frames,shuffle,end_credits,show_time,thumbs,8),"add",256,x_pos(r_width,pad,columns,8),y_pos(logo, r_height,pad,columns,8))
Layer(drop, "add", shadow_opacity, x=x_pos(r_width,pad,columns,8) + 6, y=y_pos(logo, r_height,pad,columns,8) + 3)""") : NOP
9 <= frames ? Eval("""
Layer(frame(src,r_width,r_height,frames,shuffle,end_credits,show_time,thumbs,9),"add",256,x_pos(r_width,pad,columns,9),y_pos(logo, r_height,pad,columns,9))
Layer(drop, "add", shadow_opacity, x=x_pos(r_width,pad,columns,9) + 6, y=y_pos(logo, r_height,pad,columns,9) + 3) """) : NOP
10 <= frames ? Eval("""
Layer(frame(src,r_width,r_height,frames,shuffle,end_credits,show_time,thumbs,10),"add",256,x_pos(r_width,pad,columns,10),y_pos(logo, r_height,pad,columns,10))
Layer(drop, "add", shadow_opacity, x=x_pos(r_width,pad,columns,10) + 6, y=y_pos(logo, r_height,pad,columns,10) + 3)""") : NOP
11 <= frames ? Eval("""
Layer(frame(src,r_width,r_height,frames,shuffle,end_credits,show_time,thumbs,11),"add",256,x_pos(r_width,pad,columns,11),y_pos(logo, r_height,pad,columns,11))
Layer(drop, "add", shadow_opacity, x=x_pos(r_width,pad,columns,11) + 6, y=y_pos(logo, r_height,pad,columns,11) + 3)""") : NOP
12 <= frames ? Eval("""
Layer(frame(src,r_width,r_height,frames,shuffle,end_credits,show_time,thumbs,12),"add",256,x_pos(r_width,pad,columns,12),y_pos(logo, r_height,pad,columns,12))
Layer(drop, "add", shadow_opacity, x=x_pos(r_width,pad,columns,12) + 6, y=y_pos(logo, r_height,pad,columns,12) + 3)""") : NOP
13 <= frames ? Eval("""
Layer(frame(src,r_width,r_height,frames,shuffle,end_credits,show_time,thumbs,13),"add",256,x_pos(r_width,pad,columns,13),y_pos(logo, r_height,pad,columns,13))
Layer(drop, "add", shadow_opacity, x=x_pos(r_width,pad,columns,13) + 6, y=y_pos(logo, r_height,pad,columns,13) + 3)""") : NOP
14 <= frames ? Eval("""
Layer(frame(src,r_width,r_height,frames,shuffle,end_credits,show_time,thumbs,14),"add",256,x_pos(r_width,pad,columns,14),y_pos(logo, r_height,pad,columns,14))
Layer(drop, "add", shadow_opacity, x=x_pos(r_width,pad,columns,14) + 6, y=y_pos(logo, r_height,pad,columns,14) + 3)""") : NOP
15 <= frames ? Eval("""
Layer(frame(src,r_width,r_height,frames,shuffle,end_credits,show_time,thumbs,15),"add",256,x_pos(r_width,pad,columns,15),y_pos(logo, r_height,pad,columns,15))
Layer(drop, "add", shadow_opacity, x=x_pos(r_width,pad,columns,15) + 6, y=y_pos(logo, r_height,pad,columns,15) + 3)""") : NOP
16 <= frames ? Eval("""
Layer(frame(src,r_width,r_height,frames,shuffle,end_credits,show_time,thumbs,16),"add",256,x_pos(r_width,pad,columns,16),y_pos(logo, r_height,pad,columns,16))
Layer(drop, "add", shadow_opacity, x=x_pos(r_width,pad,columns,16) + 6, y=y_pos(logo, r_height,pad,columns,16) + 3)""") : NOP
17 <= frames ? Eval("""
Layer(frame(src,r_width,r_height,frames,shuffle,end_credits,show_time,thumbs,17),"add",256,x_pos(r_width,pad,columns,17),y_pos(logo, r_height,pad,columns,17))
Layer(drop, "add", shadow_opacity, x=x_pos(r_width,pad,columns,17) + 6, y=y_pos(logo, r_height,pad,columns,17) + 3)""") : NOP
18 <= frames ? Eval("""
Layer(frame(src,r_width,r_height,frames,shuffle,end_credits,show_time,thumbs,18),"add",256,x_pos(r_width,pad,columns,18),y_pos(logo, r_height,pad,columns,18))
Layer(drop, "add", shadow_opacity, x=x_pos(r_width,pad,columns,18) + 6, y=y_pos(logo, r_height,pad,columns,18) + 3)""") : NOP
19 <= frames ? Eval("""
Layer(frame(src,r_width,r_height,frames,shuffle,end_credits,show_time,thumbs,19),"add",256,x_pos(r_width,pad,columns,19),y_pos(logo, r_height,pad,columns,19))
Layer(drop, "add", shadow_opacity, x=x_pos(r_width,pad,columns,19) + 6, y=y_pos(logo, r_height,pad,columns,19) + 3)""") : NOP
20 <= frames ? Eval("""
Layer(frame(src,r_width,r_height,frames,shuffle,end_credits,show_time,thumbs,20),"add",256,x_pos(r_width,pad,columns,20),y_pos(logo, r_height,pad,columns,20))
Layer(drop, "add", shadow_opacity, x=x_pos(r_width,pad,columns,20) + 6, y=y_pos(logo, r_height,pad,columns,20) + 3)""") : NOP
21 <= frames ? Eval("""
Layer(frame(src,r_width,r_height,frames,shuffle,end_credits,show_time,thumbs,21),"add",256,x_pos(r_width,pad,columns,21),y_pos(logo, r_height,pad,columns,21))
Layer(drop, "add", shadow_opacity, x=x_pos(r_width,pad,columns,21) + 6, y=y_pos(logo, r_height,pad,columns,21) + 3)""") : NOP
22 <= frames ? Eval("""
Layer(frame(src,r_width,r_height,frames,shuffle,end_credits,show_time,thumbs,22),"add",256,x_pos(r_width,pad,columns,22),y_pos(logo, r_height,pad,columns,22))
Layer(drop, "add", shadow_opacity, x=x_pos(r_width,pad,columns,22) + 6, y=y_pos(logo, r_height,pad,columns,22) + 3)""") : NOP
23 <= frames ? Eval("""
Layer(frame(src,r_width,r_height,frames,shuffle,end_credits,show_time,thumbs,23),"add",256,x_pos(r_width,pad,columns,23),y_pos(logo, r_height,pad,columns,23))
Layer(drop, "add", shadow_opacity, x=x_pos(r_width,pad,columns,23) + 6, y=y_pos(logo, r_height,pad,columns,23) + 3)""") : NOP
24 <= frames ? Eval("""
Layer(frame(src,r_width,r_height,frames,shuffle,end_credits,show_time,thumbs,24),"add",256,x_pos(r_width,pad,columns,24),y_pos(logo, r_height,pad,columns,24))
Layer(drop, "add", shadow_opacity, x=x_pos(r_width,pad,columns,24) + 6, y=y_pos(logo, r_height,pad,columns,24) + 3)""") : NOP
25 <= frames ? Eval("""
Layer(frame(src,r_width,r_height,frames,shuffle,end_credits,show_time,thumbs,25),"add",256,x_pos(r_width,pad,columns,25),y_pos(logo, r_height,pad,columns,25))
Layer(drop, "add", shadow_opacity, x=x_pos(r_width,pad,columns,25) + 6, y=y_pos(logo, r_height,pad,columns,25) + 3)""") : NOP

And screenshot:

http://img260.imageshack.us/img260/9872/sshot1d.th.png (http://img260.imageshack.us/img260/9872/sshot1d.png)

Update:

added drop shadow effect (needs shadow.png image either from attachment or from here (http://img412.imageshack.us/img412/1597/shadowg.png))
added option to avoid start/end credits (end_credits variable needs to be set to "true"; it's "false" by default)

StainlessS
21st December 2009, 14:50
For Avisynth language extension Gscript, IF,ELSE,FOR,NEXT:-

http://forum.doom9.org/showthread.php?t=147846

WOW, you have a really WIDE screen. Makes it hard work scrolling side to side to access the scroll up/down bar.
I would edit you text width if I were you, too much like hard work looking at your script as it is. :)

EDIT:-

Take a look at:-

http://avisynth.org/vcmohan/

Look at Hollywood squares

Keiyakusha
21st December 2009, 14:55
When you open file by DirectShowSource, FPS is not accurate (but close enough). However I doubt if this is good to print these numbers on the thumbnail.
By the way, how about anamorphic videos? Is there a way to correct aspect ratio?

2E7AH
22nd December 2009, 20:24
They are accurate here (if you mean about frame number, as for FPS you have also num/den printed)
About printing them, I thought about that: Should they be printed as frame numbers or in time format?
I thought to print them both, but left only frame numbers at last, as you can exactly know which frame is printed
I should have made that as option and make function for converting frame number to time format, which I will if I change the script in future

I have no answer to your last question

@Stainless: thanks for the links :)

I found Gscript just after I posted the script and browsed the forum. I can't know why developers didn't add those common functions, but probably there is some usage reason for that.
It's great to have them

some interesting plugins by Mohan, I'll try them if some idea pops

thanks for your comments

Keiyakusha
22nd December 2009, 20:50
They are accurate here (if you mean about frame number, as for FPS you have also num/den printed
Normally for source video with fps ~23.976 we should see this.
http://imgur.com/Zgb6f.jpg
But using DSS we will get something like this:
http://imgur.com/161Ly.jpg
Thats what I mean

Also your video seems to have a bit wrong FPS. I was confused by that. Error caused by DSS is indeed smaller.

2E7AH
22nd December 2009, 21:04
OK, I see what you mean. Thanks for pointing it.
But what do you suggest instead DSS?

IanB
22nd December 2009, 21:09
The DirectShow API expreses all times and related info in 100 nanosecond units. The plugin is just using the information available to it, i.e. average time per frame = 0.0417083 seconds. You have to know your source and make a choice whether 24000/1001 is appropriate on not.

This has been discussed many times :search:

Keiyakusha
22nd December 2009, 21:26
2E7AH
Actually I think DSS is fine for this purpose. I don't think there is good replacement. I just doubt that this info about FPS can be useful here. As well as info about avisynth version.
IMHO you can just strip num/den info, and attach FPS to the second line. And maybe make font larger if there is nothing else to print there.

thegame
23rd December 2009, 01:20
Thanks for this,could you upload your avisynth.png somewhere else,it is taking to long to get approved.

thanks again

2E7AH
23rd December 2009, 04:23
@thegame, here: http://avisynth.org/images/avisynth-logo-tray.png

@Keiyakusha: I guess you are right, I'll change that and add optional time format for thumbs tomorrow

thegame
23rd December 2009, 04:31
Thank you very much,much faster than waiting for approval.

now I just need to get this baby to work.

2E7AH
25th December 2009, 10:06
OK, I uploaded new script in OP (and add new thumbs) with this changes:

- possibility to display cover
- polished logo and placed at right side (until image approval can be grabbed from here (http://img43.imageshack.us/img43/3224/avisynth.png))
- added option for displaying the time instead frame number (time format is set by default)
- changed rows/columns more logically (i.e. 12 thumbs now generate 3:4 instead 4:3 as it was)
+ some tiny things

If someone is interested in vector format (EPS) for avisynth logo it can be found here (http://pastebin.com/f2eaac424)

thegame
26th December 2009, 00:34
Does this work on avi files? I have lossless avi files in Lagarith and Huffy and neither will show up.

2E7AH
27th December 2009, 02:32
I don't see problem for Lagarith, but for Huffyuv (with default RGB setting) there is some problem, which can be avoid changing line 24:
src = DirectShowSource(file, audio=false).ConvertToRGB
to:
src = DirectShowSource(file, audio=false).ConvertToYUY2.ConvertToRGB

Don't ask why :)
I changed corresponding line in OP also.

If this doesn't work for you, share your codec version and file info

thegame
27th December 2009, 02:53
THANK YOU SO MUCH,that worked,now this is a cool script.

again Thanks

~SimpleX~
10th February 2010, 20:20
I've slightly modified your script: made it a function (sorry if you don't like its name :D), modified #thumbs block with GScript, changed number of thumbs to number of rows and columns (if you set 4x5 there'll be 20 thumbs), and maybe smth else. But it's still not usable with default call (because I don't know if it's possible to get the file name from DSS, etc).

Default call: MakeThumbs(filename="Test") or MakeThumbs(src, Filename="Test")

logo.png and shadowg.png should be in the same folder as your script (not makethumbs) or you can change path to whatever you like, of course.

Didn't test it properly, though. And didn't change anything too much (don't know avisynth lang well enough to do it)

Oh, and you should have GScript.dll in your plugins folder.

And sorry for my "english" :D

Script:


function MakeThumbs (\
clip src,\
int "rows",\
int "columns",\
int "bg_width",\
int "size",\
int "shadow_opacity",\
int "pad",\
int "shuffle",\
string "font",\
string "logo",\
string "shadow",\
string "cover_name",\
string "filename",\
bool "show_time",\
bool "cover",\
bool "end_credits") {


logo = Default(logo, "logo.png")
shadow = Default(shadow, "shadow.png")

rows = Default(rows, 4)
columns = Default(columns, 4)
show_time = Default(show_time, true) # if set to "true", frames will have time as caption instead frame number
cover = Default(cover, false) # display cover.jpg (or cover_name value) which should be in source file folder or specified in cover_name as full path
cover_name = Default(cover_name, "cover.jpg")
end_credits = Default(end_credits, false) # set to "true" to reasonably try to avoid start/end credits

bg_width = Default(bg_width, 1200)
bg_color = $F5F8FA
font = Default(font, "Courier New")
shadow_opacity = Default(shadow_opacity, 160)
text_color = $000000
halo_color = $FFFFFF
size = Default(size, 20)
pad = Default(pad, 8)


filename = Default(filename, "File")

shuffle = Default(shuffle, 0) # shuffles frame matching

# below code shouldn't be changed, unless...
thumbs = columns*rows
src = src.ConvertToYUY2.ConvertToRGB
img = ImageSource(logo, pixel_type="rgb32")

c_pad = 0

r_width = round(bg_width/columns) - pad
r_height = r_width * height(src)/width(src)
bg_height = (r_height + pad) * rows + height(ImageSource(logo))
frames = floor(FrameCount(src)/thumbs)
drop = Exist(shadow) ? ImageSource(shadow, pixel_type="rgb32").LanczosResize(r_width, r_height) : BlankClip

# display

BlankClip(src, width=bg_width, height=bg_height, color=bg_color)

# info subtitles

resolution = "Resolution: " + string(Width(src)) + ":" + string(Height(src))
rate = "Frame Rate: " + string(FrameRate (src), "%.3f")
c_name = cover_name

cover == true ? Eval("""
try { c_pad = width(ImageSource(c_name))*height(ImageSource(logo))/height(ImageSource(c_name)) }
catch(err_msg) { }
c_pad != 0 ? Layer(ImageSource(c_name).ConvertToRGB32.LanczosResize(c_pad, height(ImageSource(logo))), "add", 256, pad/2): NOP """) : NOP

height(ImageSource(logo)) > 25 ? Eval("""
Subtitle("Filename: " + filename, c_pad + pad, line(1) + ceil(size/4), 0, FrameCount(src), \
font, size, text_color, halo_color, spc = 6)
nl = 3""") : NOP
height(ImageSource(logo)) > 55 ? Eval("""
Subtitle(resolution, c_pad + pad, line(nl) + ceil(size/3), 0, FrameCount(src), \
font, size, text_color, halo_color, spc = 6)
nl = 4""") : NOP
height(ImageSource(logo)) > 70 ? Eval("""
Subtitle(rate, c_pad + pad, line(nl) + ceil(size/3)*2, 0, FrameCount(src), \
font, size, text_color, halo_color, spc = 6)
nl = 5""") : NOP
height(ImageSource(logo)) > 40 ? Eval("""
Subtitle("Length: " + c_time(src, FrameCount(src)), c_pad + pad, line(nl) + ceil(size/3)*3, 0, FrameCount(src), \
font, size, text_color, halo_color, spc = 6)""") : NOP

Layer(img, "add", 224, x=bg_width-width(ImageSource(logo))-pad/2, y=2)

# thumbs
GScript("""
for (i=1, Thumbs) {
if (i <= frames) {
Layer(frame(src,r_width,r_height,frames,shuffle,end_credits,show_time,thumbs,i),"add",256,x_pos(r_width,pad,columns,i),y_pos(logo, r_height,pad,columns,i))
Layer(drop, "add", shadow_opacity, x=x_pos(r_width,pad,columns,i) + 6, y=y_pos(logo, r_height,pad,columns,i) + 3)
} else { NOP }
}
""")
}
# functions

function c_time(clip src, int frame) {
hours = floor(frame/FrameRate(src)/3600)
minutes = floor(frame/FrameRate(src)/60) - hours*60
seconds = frame/FrameRate(src) - floor(frame/FrameRate(src)/60)*60
return string(hours, "%02.0f") + ":" + String(minutes, "%02.0f") + ":" + string(seconds, "%02.3f")
}

function frame(clip src, int r_width, int r_height, int frames, int shuffle, bool end_credits, bool show_time, int thumbs, int x){
y = end_credits == true && (x == 1 || x == thumbs) ? sign(x-1) : .5

Trim(src, x*frames - round(frames*y) - rand(shuffle), 0).LanczosResize(r_width, r_height)

show_time == true ? \
ShowTime(offset_f = x*frames - round(frames*y) - rand(shuffle), x = 45, y = r_height, \
font= "Lucida Console", size = 10, text_color = $FFFFFF, halo_color = $000000) \
: \
ShowFrameNumber(scroll = true, offset = x*frames - round(frames*y) - rand(shuffle), x = 8, y = r_height, \
font= "Lucida Console", size = 10, text_color = $FFFFFF, halo_color = $000000)
}

function x_pos(int r_width, int pad, int columns, int x) {
round(pad/2) + ((x-1)-floor((x-1)/columns)*columns)*(r_width + pad)-1
}

function y_pos(val logo, int r_height, int pad, int columns, int x) {
floor((x-1)/columns) * (r_height + pad) + round(pad/2) + height(ImageSource(logo))
}

function line(x) { (x - 1) * 15 - 3 }