Implemented images loader which loads and sorts used in WF images
parent
dbad1974fe
commit
b558e379d9
|
@ -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)
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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" />
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue