Add extension source

This commit is contained in:
Mike Nolan 2022-05-21 10:37:43 -05:00
parent 9469f5432f
commit 76ce3161ec
12 changed files with 463 additions and 0 deletions

View File

@ -0,0 +1,75 @@
using Newtonsoft.Json;
using SixLabors.Fonts;
using SixLabors.ImageSharp.PixelFormats;
namespace ClockExtension
{
public class ClockData
{
public static ClockData Load(string extDir,FontCollection coll)
{
string fontDir = Path.Combine(extDir,"Fonts");
if(Directory.Exists(fontDir)){
foreach(var ttf in Directory.GetFiles(fontDir,"*.ttf"))
{
coll.Add(ttf);
}
}
string extInfoFile=Path.Combine(extDir,"ext_info.json");
if(File.Exists(extInfoFile))
{
string extInfoFileString = File.ReadAllText(extInfoFile);
var cd=JsonConvert.DeserializeObject<ClockData>(extInfoFileString);
if(cd != null)
{
cd.FilePath = extInfoFile;
FontFamily[] fam = coll.Families.ToArray();
for(int i = 0;i<fam.Length;i++)
{
if(fam[i].Name.Equals(cd.FontName,StringComparison.Ordinal))
{
cd.FontIndex=i;
break;
}
}
return cd;
}
}
return new ClockData {FilePath=extInfoFile};
}
public ClockData()
{
EnableClock=true;
DateFormat = "yyyy/MM/dd HH:mm:ss";
FontIndex=0;
FilePath="";
FontSize = 24;
ForeColor=Eto.Drawing.Colors.White;
X=16;
Y=16;
}
[JsonIgnore]
public int FontIndex {get;set;}
[JsonIgnore]
public string FilePath {get;private set;}
public bool EnableClock {get;set;}
public int X {get;set;}
public int Y {get;set;}
public string? FontName {get;set;}
public float FontSize {get;set;}
public string DateFormat {get;set;}
public Rgb ForeColor {get;set;}
public void Save()
{
string data=JsonConvert.SerializeObject(this);
File.WriteAllText(FilePath,data);
}
}
}

View File

@ -0,0 +1,154 @@
using System.Collections.ObjectModel;
using Eto.Forms;
using SixLabors.Fonts;
namespace ClockExtension
{
public class ClockDialog : Dialog
{
public ClockDialog(ClockData data,FontCollection collection,string extPath)
{
Button changeColor = new Button {Text="Change Color"};
changeColor.Click+=(sender,e)=>{
using(var ccd = new ColorDialog())
{
ccd.Color = data.ForeColor;
ccd.ColorChanged+=(sender,e)=>{
data.ForeColor=ccd.Color;
};
ccd.ShowDialog(this);
}
};
Button saveBtn = new Button {Text="Save"};
saveBtn.Click +=(sender,e)=>{
data.Save();
this.Close();
};
CheckBox enabled=new CheckBox{Text="Enable Clock"};
enabled.Checked = data.EnableClock;
enabled.CheckedChanged+=(sender,e)=>{
data.EnableClock=enabled.Checked.GetValueOrDefault();
};
NumericStepper fontSize=new NumericStepper{MinValue=6,MaxValue=65535,Value = data.FontSize,DecimalPlaces=2};
fontSize.ValueChanged+= (sender,e)=>{
data.FontSize = (float)fontSize.Value;
};
NumericStepper x=new NumericStepper {MinValue=0,MaxValue=65535,Value=data.X};
x.ValueChanged +=(sender,e)=>{
data.X=(int)x.Value;
};
NumericStepper y=new NumericStepper {MinValue=0,MaxValue=65535,Value=data.Y};
y.ValueChanged +=(sender,e)=>{
data.Y=(int)y.Value;
};
GroupBox gbox=new GroupBox{Text="Clock Position"};
DynamicLayout lytg=new DynamicLayout();
lytg.BeginVertical();
lytg.BeginHorizontal();
lytg.Add(x,true);
lytg.Add(y,true);
lytg.EndHorizontal();
lytg.EndVertical();
gbox.Content=lytg;
ObservableCollection<string> fonts = new ObservableCollection<string>();
Title="Clock Settings";
TextBox timeFormat=new TextBox();
timeFormat.PlaceholderText="yyyy/MM/dd HH:mm:ss";
timeFormat.Text=data.DateFormat;
timeFormat.TextChanged+=(sender,e)=>{
if(string.IsNullOrWhiteSpace(timeFormat.Text))
{
data.DateFormat=timeFormat.PlaceholderText;
}else{
data.DateFormat=timeFormat.Text;
}
};
DropDown down = new DropDown();
down.Tag = data;
down.DataStore = fonts;
Button browseFont=new Button {Text="Add Font"};
browseFont.Click +=(sender,e)=>{
using(var ofd=new OpenFileDialog())
{
ofd.MultiSelect=true;
ofd.Filters.Add(new FileFilter("True Type Font",".ttf"));
if(ofd.ShowDialog(this)==DialogResult.Ok)
{
foreach(var fname in ofd.Filenames){
string fontDir = Path.Combine(extPath,"Fonts");
Directory.CreateDirectory(fontDir);
string fontPath=Path.Combine(fontDir,Path.GetFileName(fname));
File.Copy(fname,fontPath);
collection.Add(fontPath);
}
}
}
DropDownRefresh(collection,fonts,down);
};
DynamicLayout lyt=new DynamicLayout();
lyt.BeginVertical();
lyt.BeginHorizontal();
lyt.Add(enabled);
lyt.EndHorizontal();
lyt.EndBeginVertical();
lyt.BeginHorizontal();
lyt.Add(down,true);
DropDownRefresh(collection,fonts,down);
if(data.FontIndex < fonts.Count)
{
down.SelectedIndex=data.FontIndex;
}else{
down.SelectedIndex=0;
}
lyt.Add(fontSize);
lyt.Add(browseFont);
lyt.EndHorizontal();
lyt.EndBeginVertical();
lyt.BeginHorizontal();
lyt.Add(timeFormat,true);
lyt.EndHorizontal();
lyt.EndBeginVertical();
lyt.BeginHorizontal();
lyt.Add(gbox,true);
lyt.EndHorizontal();
lyt.EndBeginVertical();
lyt.BeginHorizontal();
lyt.Add(changeColor,true);
lyt.Add(saveBtn,true);
lyt.EndHorizontal();
lyt.EndVertical();
this.Content=lyt;
this.Resizable=true;
}
public void SelectFont(object? sender,EventArgs e)
{
if(sender ==null)
{
return;
}
var dd=(DropDown)sender;
var coll=(ObservableCollection<string>)dd.DataStore;
var selectedFont=(ClockData)dd.Tag;
if(dd.SelectedIndex > -1){
selectedFont.FontName = coll[dd.SelectedIndex];
selectedFont.FontIndex=dd.SelectedIndex;
}
}
public void DropDownRefresh(FontCollection collection,ObservableCollection<string> fonts,DropDown dd)
{
dd.SelectedIndexChanged-=SelectFont;
fonts.Clear();
foreach(var font in collection.Families)
{
fonts.Add(font.Name);
}
dd.SelectedIndexChanged+=SelectFont;
}
}
}

View File

@ -0,0 +1,17 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Library</OutputType>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="SixLabors.Fonts" Version="1.0.0-beta17" />
<PackageReference Include="SixLabors.ImageSharp.Drawing" Version="1.0.0-beta14" />
<PackageReference Include="Tesses.TimelapseApi" Version="1.0.0" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,52 @@
using TimelapseApi;
using Eto.Forms;
using System;
using SixLabors.ImageSharp;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Processing;
using SixLabors.Fonts;
using SixLabors.ImageSharp.Drawing.Processing;
namespace ClockExtension
{
public class ClockExtension : TimelapseExtension
{
FontCollection collection = new FontCollection();
public ClockExtension()
{
collection.AddSystemFonts();
Data=new ClockData();
}
public ClockData Data {get;set;}
public override string Name => "Clock Extension";
public override Guid Id => Guid.Parse("{1cb8b576-e2e8-44d5-a8e1-e25a47eb0564}"); //https://duckduckgo.com/?q=guid&t=ffab&ia=answer
protected override void OnCreate(ExtensionFeatures features)
{
Data=ClockData.Load(GetExtensionFolder(),collection);
features.RegisterFrameHandler(ImageHandler,"Draw Clock").RegisterSettingsDialog(()=>{
return new ClockDialog(Data,collection,GetExtensionFolder());
},"Clock Settings");
}
private bool ImageHandler(Image<Rgb24> arg)
{
if(Data.EnableClock)
{
string nowTime=DateTime.Now.ToString(Data.DateFormat.Replace("\\n","\n"));
arg.Mutate((e)=>{
var font=collection.Families.Skip(Data.FontIndex).FirstOrDefault();
var f=font.CreateFont(Data.FontSize);
e.DrawText(nowTime,f,Data.ForeColor,new PointF(Data.X,Data.Y));
});
}
return true;
}
}
}

View File

@ -0,0 +1,45 @@
using TimelapseApi;
using Eto.Forms;
using System;
using SixLabors.ImageSharp;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Processing;
using SixLabors.Fonts;
namespace ClockExtension
{
public class Rgb
{
public byte Red {get;set;}
public byte Green {get;set;}
public byte Blue {get;set;}
public static implicit operator Rgb24(Rgb color)
{
return new Rgb24(color.Red,color.Green,color.Blue);
}
public static implicit operator Rgb(Color c)
{
return c.ToPixel<Rgb24>();
}
public static implicit operator Color(Rgb color)
{
return new Color(color);
}
public static implicit operator Rgb(Rgb24 color)
{
return new Rgb {Red=color.R,Green=color.G,Blue = color.B};
}
public static implicit operator Eto.Drawing.Color(Rgb color)
{
return new Eto.Drawing.Color((float)(color.Red/255.0),(float)(color.Green/255.0),(float)(color.Blue/255.0));
}
public static implicit operator Rgb(Eto.Drawing.Color color)
{
byte r=(byte)(color.R * 255);
byte g=(byte)(color.G * 255);
byte b=(byte)(color.B * 255);
return new Rgb{Red=r,Green=g,Blue=b};
}
}
}

View File

@ -0,0 +1,6 @@
{
"name": "Clock Extension",
"author": "Tesses",
"version": "1.0.0",
"description": "Draws clock on screen"
}

View File

@ -0,0 +1,4 @@
#!/bin/bash
timelapsepack install
cd ~/TimelapseNow/Timelapse.Linux
dotnet run

View File

@ -0,0 +1,83 @@
using TimelapseApi;
using System;
using SixLabors.ImageSharp;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Processing;
using SixLabors.ImageSharp.Drawing;
using SixLabors.ImageSharp.Drawing.Processing;
namespace TestPattern
{
public class TestPattern : TimelapseExtension
{
public override string Name => "Test Pattern";
public override Guid Id => Guid.Parse("{d918ac89-c07a-4ce4-a94b-c3e6c6f7a7e3}"); //https://duckduckgo.com/?q=guid&t=ffab&ia=answer
protected override void OnCreate(ExtensionFeatures features)
{
features.RegisterFrameHandler((e)=>{
if(Instance == null)
{
return true;
}
if(Instance.HasCamera)
{
return true;
}
int colW=e.Width / 7;
int widthtotalBottom = (int)(colW* 3.80);
int colH=(int)(e.Height * 0.70);
int bottomY=(int)(e.Height*0.80);
int bottomW = widthtotalBottom/3;
Action<Color,int,IImageProcessingContext> draw=(color,i,ipc)=>{
ipc.FillPolygon(color,new PointF(0+(colW*i),0),new PointF(colW + (colW*i),0),new PointF(colW + (colW*i),colH),new PointF(0+(colW*i),colH),new PointF(0+(colW*i),0));
};
Action<Color,int,IImageProcessingContext> draw_middle = (color,i,ipc)=>{
ipc.FillPolygon(color,new PointF(0+(colW*i),colH),new PointF(colW + (colW*i),colH),new PointF(colW + (colW*i),bottomY),new PointF(0+(colW*i),bottomY),new PointF(0+(colW*i),0));
};
Action<Color,int,IImageProcessingContext> draw_bottom = (color,i,ipc)=>{
ipc.FillPolygon(color,new PointF(0+(bottomW*i),bottomY),new PointF(bottomW + (bottomW*i),bottomY),new PointF(bottomW + (bottomW*i),e.Height),new PointF(0+(bottomW*i),e.Height),new PointF(0+(bottomW*i),bottomY));
};
e.Mutate((e)=>{
var white=Color.White;
var yellow = Color.Yellow;
var aqua = Color.Aqua;
var magenta =Color.Magenta;
var red=Color.Red;
var blue = Color.Blue;
var black=Color.Black;
var navy=Color.Navy;
var lime=Color.Lime;
draw(white,0,e);
draw(yellow,1,e);
draw(aqua,2,e);
draw(lime,3,e);
draw(magenta,4,e);
draw(red,5,e);
draw(blue,6,e);
draw_middle(red,2,e);
draw_middle(blue,1,e);
draw_middle(magenta,3,e);
draw_middle(lime,4,e);
draw_middle(aqua,5,e);
draw_middle(yellow,6,e);
draw_bottom(navy,0,e);
draw_bottom(white,1,e);
draw_bottom(navy,2,e);
});
return true;
},"Test Pattern",0);
}
}
}

View File

@ -0,0 +1,17 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Library</OutputType>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="SixLabors.ImageSharp.Drawing" Version="1.0.0-beta14" />
<PackageReference Include="Tesses.TimelapseApi" Version="1.0.2" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,6 @@
{
"name": "Test Pattern",
"author": "Tesses",
"version": "1.0.0",
"description": "Draws test pattern when timelapse webcam is not available"
}

View File

@ -0,0 +1,4 @@
#!/bin/bash
timelapsepack install
cd ~/TimelapseNow/Timelapse.Linux
dotnet run