Implemented images loader which loads and sorts used in WF images

fonts_experiment
Valeriy Mironov 2017-11-25 15:47:55 +02:00
parent dbad1974fe
commit b558e379d9
5 changed files with 172 additions and 18 deletions

View File

@ -8,23 +8,39 @@ namespace WatchFace.Parser.Models
{
public const int HeaderSize = 40;
private const string DialSignature = "HMDIAL\0";
private readonly byte[] _header;
public Header(byte[] header)
{
_header = header;
}
public string Signature { get; private set; } = DialSignature;
public uint Unknown { get; set; }
public uint ParametersSize { get; set; }
public string Signature => Encoding.ASCII.GetString(_header, 0, 7);
public bool IsValid => Signature == DialSignature;
public uint Unknown => BitConverter.ToUInt32(_header, 32);
public uint ParametersSize => BitConverter.ToUInt32(_header, 36);
public static Header ReadFrom(Stream fileStream)
public void WriteTo(Stream stream)
{
var buffer = new byte[HeaderSize];
fileStream.Read(buffer, 0, HeaderSize);
return new Header(buffer);
for (var i = 0; i < buffer.Length; i++) buffer[i] = 0xff;
var signature = Encoding.ASCII.GetBytes(Signature);
var unknown = BitConverter.GetBytes(Unknown);
var parametersSize = BitConverter.GetBytes(ParametersSize);
signature.CopyTo(buffer, 0);
unknown.CopyTo(buffer, 32);
parametersSize.CopyTo(buffer, 36);
stream.Write(buffer, 0, HeaderSize);
}
public static Header ReadFrom(Stream stream)
{
var buffer = new byte[HeaderSize];
stream.Read(buffer, 0, HeaderSize);
return new Header
{
Signature = Encoding.ASCII.GetString(buffer, 0, 7),
Unknown = BitConverter.ToUInt32(buffer, 32),
ParametersSize = BitConverter.ToUInt32(buffer, 36)
};
}
}
}

View File

@ -0,0 +1,125 @@
using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Reflection;
using NLog;
namespace WatchFace.Parser.Utils
{
public class ImagesLoader
{
private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
private readonly string _imagesDirectory;
private Dictionary<long, long> _mapping;
public ImagesLoader(string imagesDirectory)
{
Images = new List<Bitmap>();
_mapping = new Dictionary<long, long>();
_imagesDirectory = imagesDirectory;
}
public List<Bitmap> Images { get; }
public void Process<T>(T serializable, string path = "")
{
if (!string.IsNullOrEmpty(path)) Logger.Trace("Loading images for {0} '{1}'", path, typeof(T).Name);
long? lastImageIndexValue = null;
foreach (var kv in SortedPropertiesDictionary<T>())
{
var id = kv.Key;
var currentPath = string.IsNullOrEmpty(path)
? id.ToString()
: string.Concat(path, '.', id.ToString());
var propertyInfo = kv.Value;
var propertyType = propertyInfo.PropertyType;
dynamic propertyValue = propertyInfo.GetValue(serializable, null);
var imageIndexAttribute = (ParameterImageIndexAttribute) propertyInfo.GetCustomAttribute(
typeof(ParameterImageIndexAttribute)
);
var imagesCountAttribute = (ParameterImagesCountAttribute) propertyInfo.GetCustomAttribute(
typeof(ParameterImagesCountAttribute)
);
if (imagesCountAttribute != null && imageIndexAttribute != null)
throw new ArgumentException(
$"Property {propertyInfo.Name} can't have both ParameterImageIndexAttribute and ParameterImagesCountAttribute"
);
if (propertyType == typeof(long))
{
if (imageIndexAttribute != null)
{
lastImageIndexValue = propertyValue;
var mappedIndex = LoadImage(propertyValue);
propertyInfo.SetValue(serializable, mappedIndex);
}
else if (imagesCountAttribute != null)
{
if (lastImageIndexValue == null)
throw new ArgumentException(
$"Property {propertyInfo.Name} can't be processed becuase ImageIndex isn't present or it is zero"
);
for (var i = lastImageIndexValue + 1; i < lastImageIndexValue + propertyValue; i++)
LoadImage(i.Value);
}
}
else
{
if (imagesCountAttribute == null && imageIndexAttribute == null)
{
if (propertyValue != null)
Process(propertyValue, currentPath);
}
else
{
throw new ArgumentException(
$"Property {propertyInfo.Name} with type {propertyType.Name} can't have ParameterImageIndexAttribute or ParameterImagesCountAttribute"
);
}
}
}
}
private long LoadImage(long index)
{
if (_mapping.ContainsKey(index))
return _mapping[index];
var fileName = Path.Combine(_imagesDirectory, $"{index}.png");
var newImageIndex = Images.Count;
Images.Add((Bitmap) Image.FromFile(fileName));
_mapping[index] = newImageIndex;
return newImageIndex;
}
private static Dictionary<byte, PropertyInfo> SortedPropertiesDictionary<T>()
{
var typeInfo = typeof(T).GetTypeInfo();
var properties = new Dictionary<byte, PropertyInfo>();
foreach (var propertyInfo in typeInfo.DeclaredProperties)
{
var parameterIdAttribute =
(ParameterIdAttribute) propertyInfo.GetCustomAttribute(typeof(ParameterIdAttribute));
if (parameterIdAttribute == null)
throw new ArgumentException(
$"Class {typeInfo.Name} doesn't have ParameterIdAttribute on property {propertyInfo.Name}"
);
if (properties.ContainsKey(parameterIdAttribute.Id))
throw new ArgumentException(
$"Class {typeInfo.Name} already has ParameterIdAttribute with Id {parameterIdAttribute.Id}"
);
properties[parameterIdAttribute.Id] = propertyInfo;
}
return properties.OrderBy(kv => kv.Key).ToDictionary(kv => kv.Key, kv => kv.Value);
}
}
}

View File

@ -84,6 +84,7 @@
<Compile Include="Reader.cs" />
<Compile Include="Utils\BitWriter.cs" />
<Compile Include="Utils\ParameterImagesCountAttribute.cs" />
<Compile Include="Utils\ImagesLoader.cs" />
<Compile Include="Utils\ParametersConverter.cs" />
<Compile Include="Utils\ParameterImageIndexAttribute.cs" />
<Compile Include="Utils\ParameterIdAttribute.cs" />

View File

@ -1,7 +1,9 @@
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using NLog;
using WatchFace.Parser.Utils;
using WatchFace.Parser.Models;
namespace WatchFace.Parser
{
@ -9,11 +11,13 @@ namespace WatchFace.Parser
{
private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
private readonly FileStream _fileStream;
private readonly Stream _stream;
private readonly List<Bitmap> _images;
public Writer(FileStream streamReader)
public Writer(Stream stream, List<Bitmap> images)
{
_fileStream = streamReader;
_stream = stream;
_images = images;
}
public void Write(WatchFace watchFace)
@ -26,6 +30,9 @@ namespace WatchFace.Parser
parameter.Write(memoryStream);
encodedParameters[parameter.Id] = memoryStream;
}
var header = new Header {ParametersSize = 20};
header.WriteTo(_stream);
}
}
}

View File

@ -70,7 +70,8 @@ namespace WatchFace
var watchFace = ReadConfig(inputFileName);
var outputFileName = Path.ChangeExtension(inputFileName, "bin");
SetupLogger(Path.ChangeExtension(outputFileName, ".log"));
WriteWatchFace(outputFileName, watchFace);
var imagesDirectory = Path.GetDirectoryName(inputFileName);
WriteWatchFace(outputFileName, imagesDirectory, watchFace);
}
private static void UnpackWatchFace(string inputFileName)
@ -105,14 +106,18 @@ namespace WatchFace
new ResourcesExtractor(images).Extract(outputDirectory);
}
private static void WriteWatchFace(string outputFileName, Parser.WatchFace watchFace)
private static void WriteWatchFace(string outputFileName, string imagesDirectory, Parser.WatchFace watchFace)
{
Logger.Debug("Writing watch face to '{0}'", outputFileName);
try
{
Logger.Debug("Reading referenced images from '{0}'", imagesDirectory);
var imagesReader = new ImagesLoader(imagesDirectory);
imagesReader.Process(watchFace);
Logger.Debug("Writing watch face to '{0}'", outputFileName);
using (var fileStream = File.OpenWrite(outputFileName))
{
var writer = new Writer(fileStream);
var writer = new Writer(fileStream, imagesReader.Images);
writer.Write(watchFace);
fileStream.Flush();
}