Compare commits

...

5 Commits

Author SHA1 Message Date
Valeriy Mironov 9c028a9c07 Added unpacking of 32-bit images appeared in some new official WFs 2019-05-04 11:47:08 +03:00
Valeriy Mironov 4ad3537a26 Added support for non image resources 2019-05-04 11:44:19 +03:00
Valeriy Mironov baa352661d Revert "Added unpacking of 32-bit images appeared in some new official WFs"
This reverts commit 1c3663b65d.
2019-05-02 20:45:29 +03:00
Valeriy Mironov 948fd521cc WIP on new elemens 2019-02-02 23:22:00 +02:00
Valeriy Mironov 1c3663b65d Added unpacking of 32-bit images appeared in some new official WFs 2018-08-20 01:53:54 +03:00
30 changed files with 476 additions and 91 deletions

View File

@ -4,6 +4,7 @@
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/PLACE_ACCESSORHOLDER_ATTRIBUTE_ON_SAME_LINE_EX/@EntryValue">NEVER</s:String>
<s:String x:Key="/Default/Environment/Hierarchy/PsiConfigurationSettingsKey/CustomLocation/@EntryValue">C:\Users\valeronm\AppData\Local\JetBrains\Transient\ReSharperPlatformVs15\v11_048a238b\SolutionCaches</s:String>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpKeepExistingMigration/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpUseContinuousIndentInsideBracesMigration/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002ECSharpPlaceAttributeOnSameLineMigration/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EMigrateBlankLinesAroundFieldToBlankLinesAroundProperty/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EMigrateThisQualifierSettings/@EntryIndexedValue">True</s:Boolean>

View File

@ -18,12 +18,16 @@ namespace Resources
public void Extract(string outputDirectory)
{
for (var i = 0; i < _descriptor.Images.Count; i++)
for (var i = 0; i < _descriptor.Resources.Count; i++)
{
var resource = _descriptor.Resources[i];
var numericPart = i.ToString().PadLeft(ImageLoader.NumericPartLength, '0');
var fileName = Path.Combine(outputDirectory, numericPart + ".png");
var fileName = Path.Combine(outputDirectory, numericPart + resource.Extension);
Logger.Debug("Extracting {0}...", fileName);
_descriptor.Images[i].Save(fileName, ImageFormat.Png);
using (var fileStream = File.OpenWrite(fileName))
resource.ExportTo(fileStream);
}
}
}

View File

@ -40,7 +40,7 @@ namespace Resources
ResourcesCount = header.ResourcesCount,
Version = header.Version,
Unknown = (header as NewHeader)?.Unknown,
Images = new Reader(stream).Read(header.ResourcesCount)
Resources = new Reader(stream).Read(header.ResourcesCount)
};
}
}

View File

@ -29,14 +29,14 @@ namespace Resources
WriteOldHeader(descriptor);
Logger.Trace("Writing images...");
new Writer(_stream).Write(descriptor.Images);
new Writer(_stream).Write(descriptor.Resources);
}
private void WriteOldHeader(FileDescriptor descriptor)
{
var header = new Header
{
ResourcesCount = (uint)descriptor.Images.Count,
ResourcesCount = (uint)descriptor.Resources.Count,
Version = descriptor.Version.Value
};
Logger.Trace("Writing resources header...");

View File

@ -1,5 +1,4 @@
using System;
using System.Drawing;
using System.Drawing;
using System.IO;
using BumpKit;
using NLog;
@ -29,10 +28,20 @@ namespace Resources.Image
{
var signature = _reader.ReadChars(4);
if (signature[0] != 'B' || signature[1] != 'M')
throw new ArgumentException("Image signature doesn't match.");
throw new InvalidResourceException("Image signature doesn't match.");
ReadHeader();
ReadPalette();
if (_paletteColors > 256)
throw new InvalidResourceException(
"Too many palette colors.");
if (_paletteColors > 0)
ReadPalette();
else if (_bitsPerPixel == 8 || _bitsPerPixel == 16 || _bitsPerPixel == 24 || _bitsPerPixel == 32)
Logger.Trace("The image doesn't use a palette.");
else
throw new InvalidResourceException(
"The image format is not supported. Please report the issue on https://bitbucket.org/valeronm/amazfitbiptools");
return ReadImage();
}
@ -66,7 +75,6 @@ namespace Resources.Image
if (padding != 0) Logger.Warn("Palette item {0} last byte is not zero: {1:X2}", i, padding);
var isColorValid = (r == 0 || r == 0xff) && (g == 0 || g == 0xff) && (b == 0 || b == 0xff);
if (isColorValid)
Logger.Trace("Palette item {0}: R {1:X2}, G {2:X2}, B {3:X2}", i, r, g, b);
else
@ -78,6 +86,16 @@ namespace Resources.Image
}
private Bitmap ReadImage()
{
if (_paletteColors > 0) return ReadPaletteImage();
if (_bitsPerPixel == 8) return Read8BitImage();
if (_bitsPerPixel == 16) return Read16BitImage();
if (_bitsPerPixel == 24) return Read24BitImage();
if (_bitsPerPixel == 32) return Read32BitImage();
throw new InvalidResourceException($"Unsupported bits per pixel value: {_bitsPerPixel}");
}
private Bitmap ReadPaletteImage()
{
var image = new Bitmap(_width, _height);
using (var context = image.CreateUnsafeContext())
@ -89,11 +107,104 @@ namespace Resources.Image
for (var x = 0; x < _width; x++)
{
var pixelColorIndex = bitReader.ReadBits(_bitsPerPixel);
var color = _palette[(int) pixelColorIndex];
var color = _palette[(int)pixelColorIndex];
context.SetPixel(x, y, color);
}
}
}
return image;
}
private Bitmap Read8BitImage()
{
var image = new Bitmap(_width, _height);
using (var context = image.CreateUnsafeContext())
{
for (var y = 0; y < _height; y++)
{
var rowBytes = _reader.ReadBytes(_rowLengthInBytes);
for (var x = 0; x < _width; x++)
{
var data = rowBytes[x];
var color = Color.FromArgb(0xff, data, data, data);
context.SetPixel(x, y, color);
}
}
}
return image;
}
private Bitmap Read16BitImage()
{
var image = new Bitmap(_width, _height);
using (var context = image.CreateUnsafeContext())
{
for (var y = 0; y < _height; y++)
{
var rowBytes = _reader.ReadBytes(_rowLengthInBytes);
var bitReader = new BitReader(rowBytes);
for (var x = 0; x < _width; x++)
{
var firstByte = (int)bitReader.ReadByte();
var secondByte = (int)bitReader.ReadByte();
var b = (byte)((secondByte >> 3) & 0x1f) << 3;
var g = (byte)(((firstByte >> 5) & 0x7) | ((secondByte & 0x07) << 3)) << 2;
var r = (byte)(firstByte & 0x1f) << 3;
var color = Color.FromArgb(0xff, r, g, b);
context.SetPixel(x, y, color);
}
}
}
return image;
}
private Bitmap Read24BitImage()
{
var image = new Bitmap(_width, _height);
using (var context = image.CreateUnsafeContext())
{
for (var y = 0; y < _height; y++)
{
var rowBytes = _reader.ReadBytes(_rowLengthInBytes);
var bitReader = new BitReader(rowBytes);
for (var x = 0; x < _width; x++)
{
var alpha = (int)bitReader.ReadByte();
var b = (int)(bitReader.ReadBits(5) << 3);
var g = (int)(bitReader.ReadBits(6) << 2);
var r = (int)(bitReader.ReadBits(5) << 3);
var color = Color.FromArgb(0xff - alpha, r, g, b);
context.SetPixel(x, y, color);
}
}
}
return image;
}
private Bitmap Read32BitImage()
{
var image = new Bitmap(_width, _height);
using (var context = image.CreateUnsafeContext())
{
for (var y = 0; y < _height; y++)
{
var rowBytes = _reader.ReadBytes(_rowLengthInBytes);
for (var x = 0; x < _width; x++)
{
var r = rowBytes[x * 4];
var g = rowBytes[x * 4 + 1];
var b = rowBytes[x * 4 + 2];
var alpha = rowBytes[x * 4 + 3];
var color = Color.FromArgb(0xff - alpha, r, g, b);
context.SetPixel(x, y, color);
}
}
}
return image;
}
}

View File

@ -1,9 +1,11 @@
using System.Drawing;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Linq;
using NLog;
using Resources.Image;
using Resources.Models;
namespace Resources
{
@ -12,33 +14,58 @@ namespace Resources
public static readonly int NumericPartLength = 4;
private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
public static Bitmap LoadImageForNumber(string directory, long index)
public static IResource LoadResourceForNumber(string directory, long index)
{
var strIndex = index.ToString();
var numericParts = new[]
{
index.ToString().PadLeft(4, '0'),
index.ToString().PadLeft(3, '0'),
index.ToString().PadLeft(2, '0'),
index.ToString()
};
strIndex.PadLeft(4, '0'), strIndex.PadLeft(3, '0'), strIndex.PadLeft(2, '0'), strIndex
}.Distinct();
foreach (var numericPart in numericParts.Distinct())
foreach (var numericPart in numericParts)
{
var fullFileName = Path.Combine(directory, numericPart + ".png");
if (!File.Exists(fullFileName))
{
Logger.Trace("File {0} doesn't exists.", fullFileName);
continue;
}
var resource = TryLoadBitmap(directory, numericPart);
if (resource != null) return resource;
var image = (Bitmap) System.Drawing.Image.FromFile(fullFileName);
Logger.Trace("Image was loaded from file {0}", fullFileName);
return ApplyDithering(image);
resource = TryLoadBlob(directory, numericPart);
if (resource != null) return resource;
}
throw new FileNotFoundException($"File referenced by index {index} not found.");
}
private static IResource TryLoadBitmap(string directory, string numericPart)
{
var fullFileName = Path.Combine(directory, numericPart + Models.Image.ResourceExtension);
if (!File.Exists(fullFileName))
{
Logger.Trace("File {0} doesn't exists.", fullFileName);
return null;
}
var image = (Bitmap) System.Drawing.Image.FromFile(fullFileName);
Logger.Trace("Image was loaded from file {0}", fullFileName);
var ditheredBitmap = ApplyDithering(image);
return new Models.Image(ditheredBitmap);
}
private static IResource TryLoadBlob(string directory, string numericPart)
{
var fullFileName = Path.Combine(directory, numericPart + Blob.ResourceExtension);
if (!File.Exists(fullFileName))
{
Logger.Trace("File {0} doesn't exists.", fullFileName);
return null;
}
using (var fileStream = File.OpenRead(fullFileName))
{
var data = new byte[fileStream.Length];
fileStream.Read(data, 0, data.Length);
return new Blob(data);
}
}
private static Bitmap ApplyDithering(Bitmap image)
{
var clone = new Bitmap(image.Width, image.Height, PixelFormat.Format32bppArgb);

View File

@ -0,0 +1,9 @@
using System;
namespace Resources
{
public class InvalidResourceException : Exception
{
public InvalidResourceException(string message) : base(message) { }
}
}

27
Resources/Models/Blob.cs Normal file
View File

@ -0,0 +1,27 @@
using System.IO;
namespace Resources.Models
{
public class Blob : IResource
{
public static string ResourceExtension = ".dat";
private readonly byte[] _data;
public Blob(byte[] data)
{
_data = data;
}
public string Extension => ResourceExtension;
public void WriteTo(Stream stream)
{
stream.Write(_data, 0, _data.Length);
}
public void ExportTo(Stream stream)
{
stream.Write(_data, 0, _data.Length);
}
}
}

View File

@ -1,5 +1,6 @@
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Runtime.Serialization;
namespace Resources.Models
@ -12,6 +13,6 @@ namespace Resources.Models
public byte? Version { get; set; }
[IgnoreDataMember]
public List<Bitmap> Images { get; set; } = new List<Bitmap>();
public List<IResource> Resources { get; set; } = new List<IResource>();
}
}

View File

@ -0,0 +1,11 @@
using System.IO;
namespace Resources.Models
{
public interface IResource
{
string Extension { get; }
void WriteTo(Stream stream);
void ExportTo(Stream stream);
}
}

29
Resources/Models/Image.cs Normal file
View File

@ -0,0 +1,29 @@
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
namespace Resources.Models
{
public class Image: IResource
{
public Bitmap Bitmap { get; }
public Image(Bitmap bitmap)
{
Bitmap = bitmap;
}
public static string ResourceExtension = ".png";
public string Extension => ResourceExtension;
public void WriteTo(Stream stream)
{
new Resources.Image.Writer(stream).Write(Bitmap);
}
public void ExportTo(Stream stream)
{
Bitmap.Save(stream, ImageFormat.Png);
}
}
}

View File

@ -1,8 +1,7 @@
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Collections.Generic;
using System.IO;
using NLog;
using Resources.Models;
namespace Resources
{
@ -20,32 +19,54 @@ namespace Resources
_binaryReader = new BinaryReader(_stream);
}
public List<Bitmap> Read(uint imagesTableLength)
public List<IResource> Read(uint resourcesCount)
{
var offsetsTableLength = (int) (imagesTableLength * OffsetTableItemLength);
var offsetsTableLength = (int) (resourcesCount * OffsetTableItemLength);
Logger.Trace("Reading resources offsets table with {0} elements ({1} bytes)",
imagesTableLength, offsetsTableLength
resourcesCount, offsetsTableLength
);
var imagesOffsets = _binaryReader.ReadBytes(offsetsTableLength);
var imagesOffset = _stream.Position;
Logger.Debug("Reading {0} images...", imagesTableLength);
var images = new List<Bitmap>((int) imagesTableLength);
for (var i = 0; i < imagesTableLength; i++)
var offsets = new int[resourcesCount];
for (var i = 0; i < resourcesCount; i++)
offsets[i] = _binaryReader.ReadInt32();
var resourcesOffset = (int) _stream.Position;
var fileSize = (int) _stream.Length;
Logger.Debug("Reading {0} resources...", resourcesCount);
var resources = new List<IResource>((int) resourcesCount);
for (var i = 0; i < resourcesCount; i++)
{
var imageOffset = BitConverter.ToUInt32(imagesOffsets, i * OffsetTableItemLength);
var realOffset = imageOffset + imagesOffset;
Logger.Trace("Image {0} offset is {1}...", i, imageOffset);
if (_stream.Position != realOffset)
var offset = offsets[i] + resourcesOffset;
var nextOffset = i + 1 < resourcesCount ? offsets[i + 1] + resourcesOffset : fileSize;
var length = nextOffset - offset;
Logger.Trace("Resource {0} offset: {1}, length: {2}...", i, offset, length);
if (_stream.Position != offset)
{
var bytesGap = realOffset - _stream.Position;
var bytesGap = offset - _stream.Position;
Logger.Warn("Found {0} bytes gap before resource number {1}", bytesGap, i);
_stream.Seek(realOffset, SeekOrigin.Begin);
_stream.Seek(offset, SeekOrigin.Begin);
}
Logger.Debug("Reading resource {0}...", i);
try
{
var bitmap = new Image.Reader(_stream).Read();
var image = new Models.Image(bitmap);
resources.Add(image);
}
catch (InvalidResourceException)
{
Logger.Warn("Resource is not an image");
_stream.Seek(offset, SeekOrigin.Begin);
var data = new byte[length];
_stream.Read(data, 0, length);
var blob = new Blob(data);
resources.Add(blob);
}
Logger.Debug("Reading image {0}...", i);
images.Add(new Image.Reader(_stream).Read());
}
return images;
return resources;
}
}
}

12
Resources/Resource.cs Normal file
View File

@ -0,0 +1,12 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Resources
{
interface IResource
{
}
}

View File

@ -53,6 +53,10 @@
<ItemGroup>
<Compile Include="Extractor.cs" />
<Compile Include="ImageLoader.cs" />
<Compile Include="InvalidResourceException.cs" />
<Compile Include="Models\Blob.cs" />
<Compile Include="Models\Image.cs" />
<Compile Include="Models\IResource.cs" />
<Compile Include="Models\FileDescriptor.cs" />
<Compile Include="Models\Header.cs" />
<Compile Include="Utils\BitReader.cs" />

View File

@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Drawing;
using System.IO;
using NLog;
using Resources.Models;
namespace Resources
{
@ -18,30 +19,30 @@ namespace Resources
_stream = stream;
}
public void Write(List<Bitmap> images)
public void Write(List<IResource> resources)
{
var offsetsTable = new byte[images.Count * OffsetTableItemLength];
var encodedImages = new MemoryStream[images.Count];
var offsetsTable = new byte[resources.Count * OffsetTableItemLength];
var encodedResources = new MemoryStream[resources.Count];
var offset = (uint) 0;
for (var i = 0; i < images.Count; i++)
for (var i = 0; i < resources.Count; i++)
{
Logger.Trace("Image {0} offset is {1}...", i, offset);
Logger.Trace("Resource {0} offset is {1}...", i, offset);
var offsetBytes = BitConverter.GetBytes(offset);
offsetBytes.CopyTo(offsetsTable, i * OffsetTableItemLength);
var encodedImage = new MemoryStream();
Logger.Debug("Encoding image {0}...", i);
new Image.Writer(encodedImage).Write(images[i]);
Logger.Debug("Encoding resource {0}...", i);
resources[i].WriteTo(encodedImage);
offset += (uint) encodedImage.Length;
encodedImages[i] = encodedImage;
encodedResources[i] = encodedImage;
}
Logger.Trace("Writing images offsets table");
Logger.Trace("Writing resources offsets table");
_stream.Write(offsetsTable, 0, offsetsTable.Length);
Logger.Debug("Writing images");
foreach (var encodedImage in encodedImages)
Logger.Debug("Writing resources");
foreach (var encodedImage in encodedResources)
{
encodedImage.Seek(0, SeekOrigin.Begin);
encodedImage.CopyTo(_stream);

View File

@ -15,5 +15,8 @@ namespace WatchFace.Parser.Elements.ActivityElements
[ParameterId(3)]
[ParameterImageIndex]
public long? DecimalPointImageIndex { get; set; }
[ParameterId(4)]
public long? SuffixMilesImageIndex { get; set; }
}
}

View File

@ -0,0 +1,29 @@
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using WatchFace.Parser.Attributes;
using WatchFace.Parser.Models;
namespace WatchFace.Parser.Elements.BasicElements
{
public class UnknownType
{
[ParameterId(1)]
public long TopLeftX { get; set; }
[ParameterId(2)]
public long TopLeftY { get; set; }
[ParameterId(3)]
public long BottomRightX { get; set; }
[ParameterId(4)]
public long BottomRightY { get; set; }
[ParameterId(5)]
[JsonConverter(typeof(StringEnumConverter))]
public TextAlignment Alignment { get; set; }
[ParameterId(6)]
public long Spacing { get; set; }
}
}

View File

@ -0,0 +1,19 @@
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using WatchFace.Parser.Attributes;
using WatchFace.Parser.Models;
namespace WatchFace.Parser.Elements.BasicElements
{
public class UnknownType14d6
{
[ParameterId(1)]
public Coordinates Unknown1 { get; set; }
[ParameterId(2)]
public Coordinates Unknown2 { get; set; }
[ParameterId(3)]
public long? Unknown3 { get; set; }
}
}

View File

@ -13,5 +13,11 @@ namespace WatchFace.Parser.Elements
[ParameterId(3)]
public Scale Scale { get; set; }
[ParameterId(5)]
public long? Unknown5 { get; set; }
[ParameterId(6)]
public long? Unknown6 { get; set; }
}
}

View File

@ -11,5 +11,11 @@ namespace WatchFace.Parser.Elements
[ParameterId(2)]
public ImageSet WeekDay { get; set; }
[ParameterId(3)]
public DateUnknown3 Unknown3 { get; set; }
[ParameterId(4)]
public Coordinates Unknown4 { get; set; }
}
}

View File

@ -0,0 +1,11 @@
using WatchFace.Parser.Attributes;
using WatchFace.Parser.Elements.BasicElements;
namespace WatchFace.Parser.Elements.DateElements
{
public class DateUnknown3
{
[ParameterId(2)]
public UnknownType Unknown2 { get; set; }
}
}

View File

@ -22,5 +22,8 @@ namespace WatchFace.Parser.Elements
[JsonConverter(typeof(DrawingOrderJsonConverter))]
[ParameterId(5)]
public long? DrawingOrder { get; set; }
[ParameterId(9)]
public long? Unknown9 { get; set; }
}
}

View File

@ -0,0 +1,26 @@
using Newtonsoft.Json;
using WatchFace.Parser.Attributes;
using WatchFace.Parser.Elements.BasicElements;
using WatchFace.Parser.Elements.TimeElements;
using WatchFace.Parser.JsonConverters;
namespace WatchFace.Parser.Elements
{
public class UnknownType14
{
[ParameterId(1)]
public TwoDigits Unknown1 { get; set; }
[ParameterId(2)]
public TwoDigits Unknown2 { get; set; }
[ParameterId(6)]
public UnknownType14d6 Unknown6 { get; set; }
[ParameterId(7)]
public UnknownType14d6 Unknown7 { get; set; }
[ParameterId(8)]
public UnknownType14d6 Unknown8 { get; set; }
}
}

View File

@ -1,8 +1,12 @@
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Linq;
using NLog;
using Resources.Models;
using WatchFace.Parser.Models;
using Header = WatchFace.Parser.Models.Header;
using Image = Resources.Models.Image;
namespace WatchFace.Parser
{
@ -18,7 +22,8 @@ namespace WatchFace.Parser
}
public List<Parameter> Parameters { get; private set; }
public List<Bitmap> Images { get; private set; }
public List<IResource> Resources { get; private set; }
public Bitmap[] Images => Resources.OfType<Image>().Select(i => i.Bitmap).ToArray();
public void Read()
{
@ -46,7 +51,7 @@ namespace WatchFace.Parser
Logger.Trace("Watch face parameters locations were read:");
Parameters = ReadParameters(parametrsTableLength, parametersLocations);
Images = new Resources.Reader(_stream).Read((uint) imagesCount);
Resources = new Resources.Reader(_stream).Read((uint) imagesCount);
}
private List<Parameter> ReadParameters(long coordinatesTableSize, ICollection<Parameter> parametersDescriptors)

View File

@ -15,8 +15,6 @@ namespace WatchFace.Parser.Utils
var result = new List<Parameter>();
var currentType = typeof(T);
if (!string.IsNullOrEmpty(path))
Logger.Trace("{0} '{1}'", path, currentType.Name);
foreach (var kv in ElementsHelper.SortedProperties<T>())
{
var id = kv.Key;
@ -52,13 +50,19 @@ namespace WatchFace.Parser.Utils
else if (propertyType.IsGenericType && propertyType.GetGenericTypeDefinition() == typeof(List<>))
{
foreach (var item in propertyValue)
{
Logger.Trace("{0} '{1}'", currentPath, propertyInfo.Name);
result.Add(new Parameter(id, Build(item, currentPath)));
}
}
else
{
var innerParameters = Build(propertyValue, currentPath);
if (innerParameters.Count > 0)
{
Logger.Trace("{0} '{1}'", currentPath, propertyInfo.Name);
result.Add(new Parameter(id, innerParameters));
}
else
Logger.Trace("{0} '{1}': Skipped because of empty", currentPath, propertyInfo.Name);
}
@ -75,8 +79,6 @@ namespace WatchFace.Parser.Utils
var thisMethod = typeof(ParametersConverter).GetMethod(nameof(Parse));
if (!string.IsNullOrEmpty(path))
Logger.Trace("{0} '{1}'", path, currentType.Name);
foreach (var parameter in descriptor)
{
var currentPath = string.IsNullOrEmpty(path)
@ -111,6 +113,7 @@ namespace WatchFace.Parser.Utils
}
else if (propertyType.IsGenericType && propertyType.GetGenericTypeDefinition() == typeof(List<>))
{
Logger.Trace("{0} '{1}'", currentPath, propertyInfo.Name);
dynamic propertyValue = propertyInfo.GetValue(result, null);
if (propertyValue == null)
{
@ -132,6 +135,7 @@ namespace WatchFace.Parser.Utils
}
else
{
Logger.Trace("{0} '{1}'", currentPath, propertyInfo.Name);
dynamic propertyValue = propertyInfo.GetValue(result, null);
if (propertyValue != null)
throw new ArgumentException($"Parameter {parameter.Id} is already set for {currentType.Name}");

View File

@ -1,31 +1,35 @@
using System;
using NLog;
using Resources;
using System;
using System.Collections.Generic;
using System.Drawing;
using NLog;
using Resources;
using System.Linq;
using Resources.Models;
using WatchFace.Parser.Attributes;
using Image = Resources.Models.Image;
namespace WatchFace.Parser.Utils
{
public class ImagesLoader
public class ResourcesLoader
{
private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
private readonly string _imagesDirectory;
private readonly Dictionary<long, long> _mapping;
public ImagesLoader(string imagesDirectory)
public ResourcesLoader(string imagesDirectory)
{
Images = new List<Bitmap>();
Resources = new List<IResource>();
_mapping = new Dictionary<long, long>();
_imagesDirectory = imagesDirectory;
}
public List<Bitmap> Images { get; }
public List<IResource> Resources { get; }
public Bitmap[] Images => Resources.OfType<Image>().Select(i => i.Bitmap).ToArray();
public void Process<T>(T serializable, string path = "")
{
if (!string.IsNullOrEmpty(path)) Logger.Trace("Loading images for {0} '{1}'", path, typeof(T).Name);
if (!string.IsNullOrEmpty(path)) Logger.Trace("Loading resources for {0} '{1}'", path, typeof(T).Name);
long? lastImageIndexValue = null;
@ -67,7 +71,7 @@ namespace WatchFace.Parser.Utils
{
if (lastImageIndexValue == null)
throw new ArgumentException(
$"Property {propertyInfo.Name} can't be processed becuase ImageIndex isn't present or it is zero"
$"Property {propertyInfo.Name} can't be processed because ImageIndex isn't present or it is zero"
);
var imagesCount = propertyType.IsGenericType
@ -102,9 +106,10 @@ namespace WatchFace.Parser.Utils
if (_mapping.ContainsKey(index))
return _mapping[index];
var newImageIndex = Images.Count;
var newImageIndex = Resources.Count;
Logger.Trace("Loading image {0}...", newImageIndex);
Images.Add(ImageLoader.LoadImageForNumber(_imagesDirectory, index));
var resource = ImageLoader.LoadResourceForNumber(_imagesDirectory, index);
Resources.Add(resource);
_mapping[index] = newImageIndex;
return newImageIndex;
}

View File

@ -59,16 +59,20 @@
<Compile Include="Elements\BasicElements\Coordinates.cs" />
<Compile Include="Elements\BasicElements\Image.cs" />
<Compile Include="Elements\BasicElements\ImageSet.cs" />
<Compile Include="Elements\BasicElements\UnknownType14d6.cs" />
<Compile Include="Elements\BasicElements\UnknownType.cs" />
<Compile Include="Elements\BasicElements\Number.cs" />
<Compile Include="Elements\BasicElements\Scale.cs" />
<Compile Include="Elements\Battery.cs" />
<Compile Include="Elements\Date.cs" />
<Compile Include="Elements\DateElements\DateUnknown3.cs" />
<Compile Include="Elements\DateElements\MonthAndDay.cs" />
<Compile Include="Elements\DateElements\OneLineMonthAndDay.cs" />
<Compile Include="Elements\DateElements\SeparateMonthAndDay.cs" />
<Compile Include="Elements\StepsProgress.cs" />
<Compile Include="Elements\Status.cs" />
<Compile Include="Elements\StatusElements\Switch.cs" />
<Compile Include="Elements\UnknownType14.cs" />
<Compile Include="Elements\Time.cs" />
<Compile Include="Elements\TimeElements\AmPm.cs" />
<Compile Include="Elements\TimeElements\TwoDigits.cs" />
@ -156,7 +160,7 @@
<Compile Include="Attributes\ParameterImagesCountAttribute.cs" />
<Compile Include="Utils\DrawingOrderIterator.cs" />
<Compile Include="Utils\ElementsHelper.cs" />
<Compile Include="Utils\ImagesLoader.cs" />
<Compile Include="Utils\ResourcesLoader.cs" />
<Compile Include="Utils\ParametersConverter.cs" />
<Compile Include="Attributes\ParameterImageIndexAttribute.cs" />
<Compile Include="Attributes\ParameterIdAttribute.cs" />

View File

@ -31,5 +31,8 @@ namespace WatchFace.Parser
[ParameterId(10)]
public AnalogDialFace AnalogDialFace { get; set; }
[ParameterId(14)]
public UnknownType14 Unknown14 { get; set; }
}
}

View File

@ -2,18 +2,20 @@
using System.Drawing;
using System.IO;
using NLog;
using Resources.Models;
using WatchFace.Parser.Models;
using Header = WatchFace.Parser.Models.Header;
namespace WatchFace.Parser
{
public class Writer
{
private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
private readonly List<Bitmap> _images;
private readonly List<IResource> _images;
private readonly Stream _stream;
public Writer(Stream stream, List<Bitmap> images)
public Writer(Stream stream, List<IResource> images)
{
_stream = stream;
_images = images;

View File

@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Linq;
using System.Reflection;
using BumpKit;
using Newtonsoft.Json;
@ -14,6 +15,7 @@ using Resources.Models;
using WatchFace.Parser;
using WatchFace.Parser.Models;
using WatchFace.Parser.Utils;
using Image = System.Drawing.Image;
using Reader = WatchFace.Parser.Reader;
using Writer = WatchFace.Parser.Writer;
@ -132,11 +134,10 @@ namespace WatchFace
var watchFace = ParseResources(reader);
if (watchFace == null) return;
GeneratePreviews(reader.Parameters, reader.Images.ToArray(), outputDirectory, baseName);
GeneratePreviews(reader.Parameters, reader.Images, outputDirectory, baseName);
Logger.Debug("Exporting resources to '{0}'", outputDirectory);
var reDescriptor = new FileDescriptor {Images = reader.Images};
var reDescriptor = new FileDescriptor {Resources = reader.Resources};
new Extractor(reDescriptor).Extract(outputDirectory);
ExportWatchFaceConfig(watchFace, Path.Combine(outputDirectory, $"{baseName}.json"));
}
@ -173,13 +174,13 @@ namespace WatchFace
}
var i = 0;
var images = new List<Bitmap>();
var images = new List<IResource>();
while (resDescriptor.ResourcesCount == null || i < resDescriptor.ResourcesCount.Value)
{
try
{
var image = ImageLoader.LoadImageForNumber(inputDirectory, i);
images.Add(image);
var resource = ImageLoader.LoadResourceForNumber(inputDirectory, i);
images.Add(resource);
}
catch (FileNotFoundException)
{
@ -194,7 +195,7 @@ namespace WatchFace
throw new ArgumentException(
$"The .res-file should contain {resDescriptor.ResourcesCount.Value} images but was loaded {images.Count} images.");
resDescriptor.Images = images;
resDescriptor.Resources = images;
using (var stream = File.OpenWrite(outputFileName))
{
@ -223,19 +224,19 @@ namespace WatchFace
try
{
Logger.Debug("Reading referenced images from '{0}'", imagesDirectory);
var imagesReader = new ImagesLoader(imagesDirectory);
var imagesReader = new ResourcesLoader(imagesDirectory);
imagesReader.Process(watchFace);
Logger.Trace("Building parameters for watch face...");
var descriptor = ParametersConverter.Build(watchFace);
var baseFilename = Path.GetFileNameWithoutExtension(outputFileName);
GeneratePreviews(descriptor, imagesReader.Images.ToArray(), outputDirectory, baseFilename);
GeneratePreviews(descriptor, imagesReader.Images, outputDirectory, baseFilename);
Logger.Debug("Writing watch face to '{0}'", outputFileName);
using (var fileStream = File.OpenWrite(outputFileName))
{
var writer = new Writer(fileStream, imagesReader.Images);
var writer = new Writer(fileStream, imagesReader.Resources);
writer.Write(descriptor);
fileStream.Flush();
}