249 lines
12 KiB
C#
249 lines
12 KiB
C#
using System;
|
|
using System.Collections.Concurrent;
|
|
using System.Collections.Generic;
|
|
using System.Configuration;
|
|
using System.Data;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using System.Text;
|
|
using System.Threading.Tasks;
|
|
using System.Windows;
|
|
using System.Windows.Media;
|
|
using System.Windows.Media.Imaging;
|
|
using System.Windows.Navigation;
|
|
|
|
namespace RBG_Server
|
|
{
|
|
/// <summary>
|
|
/// Interaction logic for App.xaml
|
|
/// </summary>
|
|
public partial class App : Application
|
|
{
|
|
public static App Context { get; private set; }
|
|
public GameServer BoardGameServer {get;}
|
|
public CommunicationHandler GameCommunicationHandler { get; private set;}
|
|
|
|
protected static readonly SolidColorBrush RED_BRUSH = new(Color.FromRgb(255, 0, 0));
|
|
protected static readonly SolidColorBrush BLUE_BRUSH = new(Color.FromRgb(0, 0, 255));
|
|
protected static readonly SolidColorBrush GREEN_BRUSH = new(Color.FromRgb(0, 255, 0));
|
|
|
|
public const string MIP_LOW = "_mip_low";
|
|
public const string MIP_MEDIUM = "_mip_med";
|
|
public const string MIP_HIGH = "_mip_high";
|
|
public const string MIP_RAW = "_mip_raw";
|
|
|
|
protected override void OnStartup(StartupEventArgs e)
|
|
{
|
|
base.OnStartup(e);
|
|
Context = this;
|
|
GameCommunicationHandler = new CommunicationHandler();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Loads the specified files from disk, creating mip maps as appropriate
|
|
/// </summary>
|
|
/// <param name="selectedFiles"></param>
|
|
/// <param name="isSprite"></param>
|
|
/// <param name="spriteLimit"></param>
|
|
void LoadFiles(string[] selectedFiles, bool isSprite=false, int spriteLimit=128)
|
|
{
|
|
// Continue in parallel
|
|
_ = Parallel.ForEach(selectedFiles, (file) =>
|
|
{
|
|
LoadFile(file);
|
|
});
|
|
}
|
|
/// <summary>
|
|
/// Loads a singular file from disk, generating Mip maps as required
|
|
/// </summary>
|
|
/// <param name="path"></param>
|
|
void LoadFile(string path, bool isSprite=true)
|
|
{
|
|
// Check if the file is a .gif, first.
|
|
using FileStream fs = File.OpenRead(path);
|
|
LoadStream(fs, path, isSprite);
|
|
|
|
}
|
|
|
|
public void LoadStream(Stream source, string path, bool isSprite)
|
|
{
|
|
long srcStart = source.Position;
|
|
byte[] vs = new byte[6]; // First 6 bytes is the gif specifier
|
|
source.Read(vs, 0, 6);
|
|
source.Position = srcStart;
|
|
string magicNumber = Encoding.ASCII.GetString(vs);
|
|
if (magicNumber == "GIF87a" || magicNumber == "GIF89a")
|
|
{
|
|
// Gif file, replace with a layered .png
|
|
GifBitmapDecoder decoder = new(source, BitmapCreateOptions.None, BitmapCacheOption.Default);
|
|
// Obtain each .gif frame
|
|
BitmapFrame[] frames = new BitmapFrame[decoder.Frames.Count];
|
|
decoder.Frames.CopyTo(frames, 0);
|
|
// Get frame sizes
|
|
int height = frames[0].PixelHeight;
|
|
int width = frames[0].PixelWidth;
|
|
// The lowest mip is static, using either the thumb or first frame
|
|
if (decoder.Thumbnail != null)
|
|
{
|
|
double scaleRate = 32 / (double)Math.Max(height, width);
|
|
MemoryStream ms = ScaleImage(decoder.Thumbnail, scaleRate);
|
|
_ = GameCommunicationHandler.ImageCollection.TryAdd(Path.GetFileNameWithoutExtension(path) + MIP_LOW + Path.GetExtension(path), new CachedByteArray(ms.ToArray()));
|
|
}
|
|
else
|
|
{
|
|
double scaleRate = 32 / (double)Math.Max(height, width);
|
|
MemoryStream ms = ScaleImage(frames[0], scaleRate);
|
|
_ = GameCommunicationHandler.ImageCollection.TryAdd(Path.GetFileNameWithoutExtension(path) + MIP_LOW + Path.GetExtension(path), new CachedByteArray(ms.ToArray()));
|
|
}
|
|
// The remaining mips are animated
|
|
if (width >= 128 || height >= 128)
|
|
{
|
|
double scaleRate = 128 / (double)Math.Max(height, width);
|
|
MemoryStream ms = ScaleAnimatedImage(frames, scaleRate);
|
|
_ = GameCommunicationHandler.ImageCollection.TryAdd(Path.GetFileNameWithoutExtension(path) + MIP_MEDIUM + Path.GetExtension(path), new CachedByteArray(ms.ToArray()));
|
|
}
|
|
if (width >= 512 || height >= 512)
|
|
{
|
|
double scaleRate = 512 / (double)Math.Max(height, width);
|
|
MemoryStream ms = ScaleAnimatedImage(frames, scaleRate);
|
|
_ = GameCommunicationHandler.ImageCollection.TryAdd(Path.GetFileNameWithoutExtension(path) + MIP_HIGH + Path.GetExtension(path), new CachedByteArray(ms.ToArray()));
|
|
}
|
|
if (width >= 512 || height >= 512)
|
|
{
|
|
// Just re-encode the gif to .png
|
|
PngBitmapEncoder encoder = new();
|
|
foreach (BitmapFrame frame in frames)
|
|
{
|
|
encoder.Frames.Add(frame);
|
|
}
|
|
MemoryStream ms = new();
|
|
encoder.Save(ms);
|
|
_ = GameCommunicationHandler.ImageCollection.TryAdd(Path.GetFileNameWithoutExtension(path) + MIP_RAW + Path.GetExtension(path), new CachedByteArray(ms.ToArray()));
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
// Regular image file
|
|
// Create the bitmap to get the current intrinsics
|
|
BitmapImage bitmapImage = new();
|
|
bitmapImage.BeginInit();
|
|
bitmapImage.StreamSource = source;
|
|
bitmapImage.CreateOptions = BitmapCreateOptions.IgnoreColorProfile | BitmapCreateOptions.PreservePixelFormat;
|
|
bitmapImage.CacheOption = BitmapCacheOption.Default;
|
|
bitmapImage.EndInit();
|
|
int height = bitmapImage.PixelHeight;
|
|
int width = bitmapImage.PixelWidth;
|
|
|
|
// Behaviour depends on the required image
|
|
if (isSprite)
|
|
{
|
|
// Sprites should have a low mip-map, and the medium
|
|
// Low = 32*32
|
|
// Medium = 128*128
|
|
// High = 512*512 or image size if less than 1024
|
|
if (width >= 32 || height >= 32)
|
|
{
|
|
double scaleRate = 32 / (double)Math.Max(height, width);
|
|
MemoryStream ms = ScaleImage(bitmapImage, scaleRate);
|
|
_ = GameCommunicationHandler.ImageCollection.TryAdd(Path.GetFileNameWithoutExtension(path) + MIP_LOW + Path.GetExtension(path), new CachedByteArray(ms.ToArray()));
|
|
}
|
|
if (width >= 128 || height >= 128)
|
|
{
|
|
double scaleRate = 128 / (double)Math.Max(height, width);
|
|
MemoryStream ms = ScaleImage(bitmapImage, scaleRate);
|
|
_ = GameCommunicationHandler.ImageCollection.TryAdd(Path.GetFileNameWithoutExtension(path) + MIP_MEDIUM + Path.GetExtension(path), new CachedByteArray(ms.ToArray()));
|
|
}
|
|
if (width >= 512 || height >= 512)
|
|
{
|
|
double scaleRate = 512 / (double)Math.Max(height, width);
|
|
MemoryStream ms = ScaleImage(bitmapImage, scaleRate);
|
|
_ = GameCommunicationHandler.ImageCollection.TryAdd(Path.GetFileNameWithoutExtension(path) + MIP_HIGH + Path.GetExtension(path), new CachedByteArray(ms.ToArray()));
|
|
}
|
|
if (width >= 512 || height >= 512)
|
|
{
|
|
MemoryStream ms = new();
|
|
source.CopyTo(ms);
|
|
_ = GameCommunicationHandler.ImageCollection.TryAdd(Path.GetFileNameWithoutExtension(path) + MIP_RAW + Path.GetExtension(path), new CachedByteArray(ms.ToArray()));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Non-sprites should have a low mip-map, and the medium, but at a larger size than the sprites
|
|
// Low = 128*128
|
|
// Medium = 512*512
|
|
// High = 2048*2048
|
|
if (width >= 128 || height >= 128)
|
|
{
|
|
double scaleRate = 128 / (double)Math.Max(height, width);
|
|
MemoryStream ms = ScaleImage(bitmapImage, scaleRate);
|
|
_ = GameCommunicationHandler.ImageCollection.TryAdd(Path.GetFileNameWithoutExtension(path) + MIP_LOW + Path.GetExtension(path), new CachedByteArray(ms.ToArray()));
|
|
}
|
|
if (width >= 512 || height >= 512)
|
|
{
|
|
double scaleRate = 512 / (double)Math.Max(height, width);
|
|
MemoryStream ms = ScaleImage(bitmapImage, scaleRate);
|
|
_ = GameCommunicationHandler.ImageCollection.TryAdd(Path.GetFileNameWithoutExtension(path) + MIP_MEDIUM + Path.GetExtension(path), new CachedByteArray(ms.ToArray()));
|
|
}
|
|
if (width >= 2048 || height >= 2048)
|
|
{
|
|
double scaleRate = 2048 / (double)Math.Max(height, width);
|
|
MemoryStream ms = ScaleImage(bitmapImage, scaleRate);
|
|
_ = GameCommunicationHandler.ImageCollection.TryAdd(Path.GetFileNameWithoutExtension(path) + MIP_HIGH + Path.GetExtension(path), new CachedByteArray(ms.ToArray()));
|
|
}
|
|
if (width >= 2048 || height >= 2048)
|
|
{
|
|
MemoryStream ms = new();
|
|
source.CopyTo(ms);
|
|
_ = GameCommunicationHandler.ImageCollection.TryAdd(Path.GetFileNameWithoutExtension(path) + MIP_RAW + Path.GetExtension(path), new CachedByteArray(ms.ToArray()));
|
|
}
|
|
// Destroy old board if we are replacing
|
|
if (!string.IsNullOrEmpty(GameCommunicationHandler.BoardName))
|
|
{
|
|
GameCommunicationHandler.ImageCollection.Remove(GameCommunicationHandler.BoardName, out CachedByteArray val);
|
|
val.Dispose();
|
|
}
|
|
GameCommunicationHandler.BoardName = Path.GetFileNameWithoutExtension(path);
|
|
}
|
|
GameCommunicationHandler.ImageList.Add(Path.GetFileNameWithoutExtension(path));
|
|
}
|
|
}
|
|
|
|
static MemoryStream ScaleImage(BitmapSource source, double scaleRate)
|
|
{
|
|
TransformedBitmap modified = new();
|
|
try
|
|
{
|
|
ScaleTransform transform = new ScaleTransform(scaleRate, scaleRate);
|
|
modified.BeginInit();
|
|
modified.Source = source;
|
|
modified.Transform = transform;
|
|
modified.EndInit();
|
|
//modified = new(source, );
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
int op = 0;
|
|
}
|
|
PngBitmapEncoder encoder = new();
|
|
encoder.Frames.Add(BitmapFrame.Create(modified));
|
|
MemoryStream ms = new();
|
|
encoder.Save(ms);
|
|
return ms;
|
|
}
|
|
|
|
static MemoryStream ScaleAnimatedImage(BitmapFrame[] frames, double scaleRate)
|
|
{
|
|
PngBitmapEncoder encoder = new();
|
|
foreach (BitmapFrame frame in frames)
|
|
{
|
|
TransformedBitmap modified = new(frame, new ScaleTransform(frame.PixelWidth * scaleRate, frame.PixelHeight * scaleRate));
|
|
encoder.Frames.Add(BitmapFrame.Create(modified));
|
|
}
|
|
MemoryStream ms = new();
|
|
encoder.Save(ms);
|
|
return ms;
|
|
}
|
|
}
|
|
}
|