Skip to content

Commit

Permalink
Merge branch 'dev'
Browse files Browse the repository at this point in the history
  • Loading branch information
stevemonaco committed Nov 10, 2020
2 parents b86f294 + 1a5d7d8 commit 1d7a41f
Show file tree
Hide file tree
Showing 117 changed files with 4,112 additions and 1,467 deletions.
4 changes: 2 additions & 2 deletions ImageMagitek.Benchmarks/Snes3bppDecodeToImage.cs
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ public void DecodeNative()
var outputFileName = Path.Combine(outputDirectory, $"Native.{i}.bmp");

var image = new IndexedImage(arranger);
image.ExportImage(outputFileName, new ImageFileAdapter());
image.ExportImage(outputFileName, new ImageSharpFileAdapter());
}
}

Expand All @@ -117,7 +117,7 @@ public void DecodeGeneric()
var outputFileName = Path.Combine(outputDirectory, $"Generic.{i}.bmp");

var image = new IndexedImage(arranger);
image.ExportImage(outputFileName, new ImageFileAdapter());
image.ExportImage(outputFileName, new ImageSharpFileAdapter());
}
}
}
Expand Down
11 changes: 11 additions & 0 deletions ImageMagitek.PluginSamples/ImageMagitek.PluginSamples.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework>
</PropertyGroup>

<ItemGroup>
<ProjectReference Include="..\ImageMagitek\ImageMagitek.csproj" />
</ItemGroup>

</Project>
135 changes: 135 additions & 0 deletions ImageMagitek.PluginSamples/Snes4bppCodec.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
using System;
using ImageMagitek.Codec;

namespace ImageMagitek.PluginSample
{
public class Snes4bppCodec : IndexedCodec
{
public override string Name => "SNES 4bpp Plugin";
public override int Width { get; }
public override int Height { get; }
public override int StorageSize => 4 * Width * Height;
public override ImageLayout Layout => ImageLayout.Tiled;
public override int ColorDepth => 4;

public override int DefaultWidth => 8;
public override int DefaultHeight => 8;
public override int WidthResizeIncrement => 1;
public override int HeightResizeIncrement => 1;
public override bool CanResize => true;

private BitStream _bitStream;

public Snes4bppCodec()
{
Width = DefaultWidth;
Height = DefaultHeight;
Initialize();
}

public Snes4bppCodec(int width, int height)
{
Width = width;
Height = height;
Initialize();
}

private void Initialize()
{
_foreignBuffer = new byte[(StorageSize + 7) / 8];
_nativeBuffer = new byte[Width, Height];
_bitStream = BitStream.OpenRead(_foreignBuffer, StorageSize);
}

public override byte[,] DecodeElement(in ArrangerElement el, ReadOnlySpan<byte> encodedBuffer)
{
if (encodedBuffer.Length * 8 < StorageSize) // Decoding would require data past the end of the buffer
throw new ArgumentException(nameof(encodedBuffer));

encodedBuffer.Slice(0, _foreignBuffer.Length).CopyTo(_foreignBuffer);

_bitStream = BitStream.OpenRead(_foreignBuffer, StorageSize);

var offsetPlane1 = 0;
var offsetPlane2 = Width;
var offsetPlane3 = Width * Height * 2;
var offsetPlane4 = Width * Height * 2 + Width;

for (int y = 0; y < Height; y++)
{
for (int x = 0; x < Width; x++)
{
_bitStream.SeekAbsolute(offsetPlane1);
var bp1 = _bitStream.ReadBit();
_bitStream.SeekAbsolute(offsetPlane2);
var bp2 = _bitStream.ReadBit();
_bitStream.SeekAbsolute(offsetPlane3);
var bp3 = _bitStream.ReadBit();
_bitStream.SeekAbsolute(offsetPlane4);
var bp4 = _bitStream.ReadBit();

var palIndex = (bp1 << 0) | (bp2 << 1) | (bp3 << 2) | (bp4 << 3);
_nativeBuffer[x, y] = (byte)palIndex;

offsetPlane1++;
offsetPlane2++;
offsetPlane3++;
offsetPlane4++;
}

offsetPlane1 += Width;
offsetPlane2 += Width;
offsetPlane3 += Width;
offsetPlane4 += Width;
}

return _nativeBuffer;
}

public override ReadOnlySpan<byte> EncodeElement(in ArrangerElement el, byte[,] imageBuffer)
{
if (imageBuffer.GetLength(0) != Width || imageBuffer.GetLength(1) != Height)
throw new ArgumentException(nameof(imageBuffer));

var bs = BitStream.OpenWrite(StorageSize, 8);

var offsetPlane1 = 0;
var offsetPlane2 = Width;
var offsetPlane3 = Width * Height * 2;
var offsetPlane4 = Width * Height * 2 + Width;

for (int y = 0; y < Height; y++)
{
for (int x = 0; x < Width; x++)
{
var index = imageBuffer[x, y];

byte bp1 = (byte)(index & 1);
byte bp2 = (byte)((index >> 1) & 1);
byte bp3 = (byte)((index >> 2) & 1);
byte bp4 = (byte)((index >> 3) & 1);

bs.SeekAbsolute(offsetPlane1);
bs.WriteBit(bp1);
bs.SeekAbsolute(offsetPlane2);
bs.WriteBit(bp2);
bs.SeekAbsolute(offsetPlane3);
bs.WriteBit(bp3);
bs.SeekAbsolute(offsetPlane4);
bs.WriteBit(bp4);

offsetPlane1++;
offsetPlane2++;
offsetPlane3++;
offsetPlane3++;
}
offsetPlane1 += Width;
offsetPlane2 += Width;
offsetPlane3 += Width;
offsetPlane4 += Width;
}

return bs.Data;
}
}
}
17 changes: 11 additions & 6 deletions ImageMagitek.Services/CodecService.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
using System.Collections.Generic;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using ImageMagitek.Codec;
using ImageMagitek.Colors;
using McMaster.NETCore.Plugins;

namespace ImageMagitek.Services
{
Expand All @@ -12,24 +14,23 @@ public interface ICodecService

IEnumerable<string> GetSupportedCodecNames();
MagitekResults LoadXmlCodecs(string codecsPath);
void AddOrUpdateCodec(Type codecType);
}

public class CodecService : ICodecService
{
public ICodecFactory CodecFactory { get; private set; }

private readonly string _schemaFileName;
private readonly Palette _defaultPalette;

public CodecService(string schemaFileName, Palette defaultPalette)
public CodecService(string schemaFileName)
{
_schemaFileName = schemaFileName;
_defaultPalette = defaultPalette;
}

public MagitekResults LoadXmlCodecs(string codecsPath)
{
var formats = new Dictionary<string, GraphicsFormat>();
var formats = new Dictionary<string, IGraphicsFormat>();
var serializer = new XmlGraphicsFormatReader(_schemaFileName);
var errors = new List<string>();

Expand All @@ -43,18 +44,22 @@ public MagitekResults LoadXmlCodecs(string codecsPath)
},
fail =>
{
errors.Add($"Failed to load XML codec '{formatFileName}'");
errors.AddRange(fail.Reasons);
});
}

CodecFactory = new CodecFactory(formats, _defaultPalette);
CodecFactory = new CodecFactory(formats);

if (errors.Any())
return new MagitekResults.Failed(errors);
else
return MagitekResults.SuccessResults;
}

public void AddOrUpdateCodec(Type codecType) =>
CodecFactory.AddOrUpdateCodec(codecType);

public IEnumerable<string> GetSupportedCodecNames() => CodecFactory?.GetSupportedCodecNames();
}
}
6 changes: 5 additions & 1 deletion ImageMagitek.Services/ImageMagitek.Services.csproj
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>netstandard2.1</TargetFramework>
<TargetFramework>netcoreapp3.1</TargetFramework>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="McMaster.NETCore.Plugins" Version="1.3.1" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\ImageMagitek\ImageMagitek.csproj" />
</ItemGroup>
Expand Down
51 changes: 23 additions & 28 deletions ImageMagitek.Services/PaletteService.cs
Original file line number Diff line number Diff line change
@@ -1,60 +1,46 @@
using System.Collections.Generic;
using System.IO;
using System.Linq;
using ImageMagitek.Colors;

namespace ImageMagitek.Services
{
public interface IPaletteService
{
IColorFactory ColorFactory { get; }

Palette DefaultPalette { get; }
List<Palette> GlobalPalettes { get; }
Palette NesPalette { get; }

void LoadGlobalPalette(string paletteFileName);
Palette ReadJsonPalette(string paletteFileName);
void SetDefaultPalette(Palette pal);
void LoadNesPalette(string nesPaletteFileName);
}

public class PaletteService : IPaletteService
{
public IColorFactory ColorFactory { get; private set; }

public Palette DefaultPalette { get; private set; }
public List<Palette> GlobalPalettes { get; } = new List<Palette>();
public Palette NesPalette { get; private set; }

/// <summary>
/// Loads a palette from a JSON file and adds it to GlobalPalettes
/// </summary>
/// <param name="paletteFileName"></param>
public void LoadGlobalPalette(string paletteFileName)
public PaletteService(IColorFactory colorFactory)
{
if (!File.Exists(paletteFileName))
throw new FileNotFoundException($"{nameof(LoadGlobalPalette)}: Could not locate file {paletteFileName}");

string json = File.ReadAllText(paletteFileName);
var pal = PaletteJsonSerializer.ReadPalette(json);
GlobalPalettes.Add(pal);

if (GlobalPalettes.Count == 1)
DefaultPalette = GlobalPalettes.First();
ColorFactory = colorFactory;
}

/// <summary>
/// Loads a palette from a JSON file and sets it as the NesPalette
/// Read a palette from a JSON file
/// </summary>
/// <param name="nesPaletteFileName"></param>
public void LoadNesPalette(string nesPaletteFileName)
/// <param name="paletteFileName">Path to the JSON palette file</param>
public Palette ReadJsonPalette(string paletteFileName)
{
if (!File.Exists(nesPaletteFileName))
throw new FileNotFoundException($"{nameof(LoadNesPalette)}: Could not locate file {nesPaletteFileName}");

NesPalette = LoadJsonPalette(nesPaletteFileName);
}
if (!File.Exists(paletteFileName))
throw new FileNotFoundException($"{nameof(ReadJsonPalette)}: Could not locate file {paletteFileName}");

private Palette LoadJsonPalette(string paletteFileName)
{
string json = File.ReadAllText(paletteFileName);
return PaletteJsonSerializer.ReadPalette(json);
var pal = PaletteJsonSerializer.ReadPalette(json, ColorFactory);
return pal;
}

/// <summary>
Expand All @@ -68,5 +54,14 @@ public void SetDefaultPalette(Palette pal)

DefaultPalette = pal;
}

/// <summary>
/// Sets the NES Palette
/// </summary>
/// <param name="nesPalette"></param>
public void SetNesPalette(Palette nesPalette)
{
NesPalette = nesPalette;
}
}
}
50 changes: 50 additions & 0 deletions ImageMagitek.Services/PluginService.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
using ImageMagitek.Codec;
using McMaster.NETCore.Plugins;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;

namespace ImageMagitek.Services
{
public interface IPluginService
{
public IDictionary<string, Type> CodecPlugins { get; }

void LoadCodecPlugins(string pluginsPath);
}

public class PluginService : IPluginService
{
public IDictionary<string, Type> CodecPlugins { get; } = new Dictionary<string, Type>();

public void LoadCodecPlugins(string pluginsPath)
{
var loaders = new List<PluginLoader>();

foreach (var dir in Directory.GetDirectories(pluginsPath))
{
{
var dirName = Path.GetFileName(dir);
var pluginDll = Path.Combine(dir, dirName + ".dll");
if (File.Exists(pluginDll))
{
var codecLoader = PluginLoader.CreateFromAssemblyFile(
pluginDll,
sharedTypes: new[] { typeof(IGraphicsCodec) });

var pluginTypes = codecLoader.LoadDefaultAssembly()
.GetTypes()
.Where(t => typeof(IGraphicsCodec).IsAssignableFrom(t) && !t.IsAbstract);

foreach (var codecType in pluginTypes)
{
var codec = (IGraphicsCodec)Activator.CreateInstance(codecType);
CodecPlugins.Add(codec.Name, codecType);
}
}
}
}
}
}
}
Loading

0 comments on commit 1d7a41f

Please sign in to comment.