Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions CSharpOrNot/App.xaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<Application xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="Gradient.Samples.App">
<Application.Styles>
<StyleInclude Source="avares://Avalonia.Themes.Default/DefaultTheme.xaml"/>
<StyleInclude Source="avares://Avalonia.Themes.Default/Accents/BaseLight.xaml"/>
</Application.Styles>
</Application>
10 changes: 10 additions & 0 deletions CSharpOrNot/App.xaml.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
namespace Gradient.Samples {
using Avalonia;
using Avalonia.Markup.Xaml;

public class App : Application {
public override void Initialize() {
AvaloniaXamlLoader.Load(this);
}
}
}
73 changes: 73 additions & 0 deletions CSharpOrNot/BitmapTools.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
namespace Gradient.Samples {
using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.Runtime.InteropServices;

static class BitmapTools {
public static void ToBitmap(byte[] brightness, Bitmap target) {
if (target.PixelFormat != PixelFormat.Format8bppIndexed)
throw new NotSupportedException("The only supported pixel format is " + PixelFormat.Format8bppIndexed);

var bitmapData = target.LockBits(new Rectangle(new Point(), target.Size),
ImageLockMode.WriteOnly,
PixelFormat.Format8bppIndexed);

try {
Marshal.Copy(source: brightness,
startIndex: 0, length: bitmapData.Width * bitmapData.Height,
destination: bitmapData.Scan0);
} finally {
target.UnlockBits(bitmapData);
}
}

// default .NET upscaling tries to interpolate, which we avoid here
public static void Upscale(Bitmap source, Bitmap target) {
if (target.Width % source.Width != 0 || target.Height % source.Height != 0)
throw new ArgumentException();

int scaleY = target.Height / source.Height;
int scaleX = target.Width / source.Width;

var sourceData = source.LockBits(new Rectangle(new Point(), source.Size),
ImageLockMode.ReadOnly, PixelFormat.Format8bppIndexed);
try {
var targetData = target.LockBits(new Rectangle(new Point(), target.Size),
ImageLockMode.WriteOnly,
PixelFormat.Format8bppIndexed);

try {
for (int sourceY = 0; sourceY < sourceData.Height; sourceY++)
for (int sourceX = 0; sourceX < sourceData.Width; sourceX++) {
byte brightness = Marshal.ReadByte(sourceData.Scan0,
sourceY * sourceData.Width + sourceX);
for (int targetY = sourceY * scaleY;
targetY < (sourceY + 1) * scaleY;
targetY++)
for (int targetX = sourceX * scaleX;
targetX < (sourceX + 1) * scaleX;
targetX++)
Marshal.WriteByte(targetData.Scan0,
targetY * targetData.Width + targetX,
brightness);
}
} finally {
target.UnlockBits(targetData);
}
} finally {
source.UnlockBits(sourceData);
}
}

public static void SetGreyscalePalette(Bitmap bitmap) {
ColorPalette pal = bitmap.Palette;

for (int i = 0; i < 256; i++) {
pal.Entries[i] = Color.FromArgb(255, i, i, i);
}

bitmap.Palette = pal;
}
}
}
115 changes: 115 additions & 0 deletions CSharpOrNot/CSharpOrNot.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
namespace Gradient.Samples {
using System;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using numpy;
using tensorflow;
using tensorflow.keras;
using tensorflow.keras.layers;

static class CSharpOrNot
{
public static Model CreateModel(int classCount) {
var activation = tf.keras.activations.elu_fn;
const int filterCount = 8;
int[] resNetFilters = { filterCount, filterCount, filterCount };
return new Sequential(new Layer[] {
new Dropout(rate: 0.05),
Conv2D.NewDyn(filters: filterCount, kernel_size: 5, padding: "same"),
Activation.NewDyn(activation),
new MaxPool2D(pool_size: 2),
new ResNetBlock(kernelSize: 3, filters: resNetFilters, activation: activation),
new ResNetBlock(kernelSize: 3, filters: resNetFilters, activation: activation),
new ResNetBlock(kernelSize: 3, filters: resNetFilters, activation: activation),
new ResNetBlock(kernelSize: 3, filters: resNetFilters, activation: activation),
new MaxPool2D(),
new ResNetBlock(kernelSize: 3, filters: resNetFilters, activation: activation),
new ResNetBlock(kernelSize: 3, filters: resNetFilters, activation: activation),
new MaxPool2D(),
new ResNetBlock(kernelSize: 3, filters: resNetFilters, activation: activation),
new ResNetBlock(kernelSize: 3, filters: resNetFilters, activation: activation),
new AvgPool2D(pool_size: 2),
new Flatten(),
new Dense(units: classCount, activation: tf.nn.softmax_fn),
});
}

public const int Width = 64, Height = 64;
public static readonly Size Size = new Size(Width, Height);
// being opinionated here
const string Tab = " ";
const char Whitespace = '\u00FF';
public static readonly string[] IncludeExtensions = {
".cs",
".py",
".h",
".cc",
".c",
".tcl",
".java",
".sh",
};

public static ndarray<float> GreyscaleImageBytesToNumPy(byte[] inputs, int imageCount, int width, int height)
=> (dynamic)inputs.Select(b => (float)b).ToArray().NumPyCopy()
.reshape(new[] { imageCount, height, width, 1 }) / 255.0f;

public static string[] ReadCode(string filePath)
=> File.ReadAllLines(filePath)
.Select(line => line.Replace("\t", Tab))
.Select(line => {
var result = new StringBuilder(line.Length);
// replace non-ASCII characters with underscore
// also make all whitespace stand out
foreach (char c in line) {
result.Append(
c <= 32 ? Whitespace
: c >= 255 ? '_'
: c);
}
return result.ToString();
})
.ToArray();

/// <summary>
/// Copies a rectangular block of text into a byte array
/// </summary>
public static void RenderTextBlockToGreyscaleBytes(string[] lines,
Point startingPoint, Size size,
byte[] destination)
{
if (size.IsEmpty) throw new ArgumentException();
if (destination.Length < size.Width * size.Height) throw new ArgumentException();
if (startingPoint.Y == lines.Length) {
Array.Fill(destination, (byte)Whitespace);
return;
}

for (int y = 0; y < size.Height; y++) {
int sourceY = y + startingPoint.Y;
int destOffset = y * size.Width;
if (sourceY >= lines.Length) {
Array.Fill(destination, (byte)255,
startIndex: destOffset,
count: size.Width*size.Height - destOffset);
return;
}

for (int x = 0; x < size.Width; x++) {
int sourceX = x + startingPoint.X;
if (sourceX >= lines[sourceY].Length) {
Array.Fill(destination, (byte)255,
startIndex: destOffset,
count: size.Width - x);
break;
}

destination[destOffset] = (byte)lines[sourceY][sourceX];
destOffset++;
}
}
}
}
}
26 changes: 26 additions & 0 deletions CSharpOrNot/CSharpOrNot.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFrameworks>netcoreapp3.0</TargetFrameworks>
<ApplicationIcon />
<StartupObject />
<RootNamespace>Gradient.Samples</RootNamespace>
</PropertyGroup>
<ItemGroup>
<Compile Update="**\*.xaml.cs">
<DependentUpon>%(Filename)</DependentUpon>
</Compile>
<AvaloniaResource Include="**\*.xaml">
<SubType>Designer</SubType>
</AvaloniaResource>
</ItemGroup>
<ItemGroup>
<PackageReference Include="Avalonia" Version="0.8.0" />
<PackageReference Include="Avalonia.Desktop" Version="0.8.0" />
<PackageReference Include="ManyConsole.CommandLineUtils" Version="1.0.3-alpha" />
<PackageReference Include="morelinq" Version="3.2.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\ResNetBlock\ResNetBlock.csproj" />
</ItemGroup>
</Project>
31 changes: 31 additions & 0 deletions CSharpOrNot/CSharpOrNotProgram.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
namespace Gradient.Samples {
using System;
using System.Linq;
using Avalonia;
using Avalonia.Logging.Serilog;
using Gradient;
using ManyConsole.CommandLineUtils;
using tensorflow;
using tensorflow.core.protobuf.config_pb2;

static class CSharpOrNotProgram {
public static int Main(string[] args) {
GradientSetup.OptInToUsageDataCollection();
GradientSetup.UseEnvironmentFromVariable();

dynamic config = config_pb2.ConfigProto();
config.gpu_options.allow_growth = true;
tf.keras.backend.set_session(Session.NewDyn(config: config));

return ConsoleCommandDispatcher.DispatchCommand(
ConsoleCommandDispatcher.FindCommandsInSameAssemblyAs(typeof(CSharpOrNotProgram)),
args, Console.Out);
}

// Avalonia configuration, don't remove; also used by visual designer.
public static AppBuilder BuildAvaloniaApp()
=> AppBuilder.Configure<App>()
.UsePlatformDetect()
.LogToDebug();
}
}
20 changes: 20 additions & 0 deletions CSharpOrNot/CSharpOrNotWindow.xaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<Window xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="Gradient.Samples.CSharpOrNotWindow"
Title="CSharpOrNot">
<Grid RowDefinitions="Auto,*,Auto">
<TextBlock Name="Language" FontSize="24" HorizontalAlignment="Center"/>
<Grid ColumnDefinitions="3*,2*,2*" Grid.Row="1">
<TextBox Name="CodeDisplay"
FontFamily="Consolas,Monospace"
AcceptsReturn="True"/>
<Image Name="CodeImage" Grid.Column="1" Stretch="Uniform"/>
<TextBlock Name="CodeWindow" Grid.Column="2"
FontFamily="Consolas,Monospace"/>
</Grid>
<Button Name="OpenFileButton" Grid.Row="2" Click="OpenFileClick">Open File</Button>
</Grid>
</Window>
Loading