diff --git a/Resources/ImageLoader.cs b/Resources/ImageLoader.cs index 6e1a981..89beaf3 100644 --- a/Resources/ImageLoader.cs +++ b/Resources/ImageLoader.cs @@ -9,7 +9,7 @@ namespace Resources { public class ImageLoader { - public static readonly int NumericPartLength = 3; + public static readonly int NumericPartLength = 4; private static readonly Logger Logger = LogManager.GetCurrentClassLogger(); public static Bitmap LoadImageForNumber(string directory, long index) diff --git a/Resources/Resources.csproj b/Resources/Resources.csproj index 79d0b28..cd27aa1 100644 --- a/Resources/Resources.csproj +++ b/Resources/Resources.csproj @@ -35,12 +35,15 @@ ..\packages\Bumpkit.1.0.2\lib\BumpKit.dll - ..\packages\NLog.4.4.12\lib\net40\NLog.dll + ..\packages\NLog.4.5.6\lib\net40-client\NLog.dll + + + diff --git a/Resources/packages.config b/Resources/packages.config index e7a2a3e..7e4a313 100644 --- a/Resources/packages.config +++ b/Resources/packages.config @@ -1,5 +1,5 @@  - + \ No newline at end of file diff --git a/WatchFace.Parser/Models/Elements/Weather/AirPollution/AirPollutionImageElement.cs b/WatchFace.Parser/Models/Elements/Weather/AirPollution/AirPollutionImageElement.cs index 3b33df6..542e4e9 100644 --- a/WatchFace.Parser/Models/Elements/Weather/AirPollution/AirPollutionImageElement.cs +++ b/WatchFace.Parser/Models/Elements/Weather/AirPollution/AirPollutionImageElement.cs @@ -9,9 +9,9 @@ namespace WatchFace.Parser.Models.Elements public override void Draw(Graphics drawer, Bitmap[] resources, WatchState state) { - if (state.Air == AirCondition.Unknown) return; + if (state.AirQuality == AirCondition.Unknown) return; - var imageIndex = (int) state.Air; + var imageIndex = (int) state.AirQuality; Draw(drawer, resources, imageIndex); } } diff --git a/WatchFace.Parser/Models/Elements/Weather/WeatherIconsElement.cs b/WatchFace.Parser/Models/Elements/Weather/WeatherIconsElement.cs index 697c1a3..e609420 100644 --- a/WatchFace.Parser/Models/Elements/Weather/WeatherIconsElement.cs +++ b/WatchFace.Parser/Models/Elements/Weather/WeatherIconsElement.cs @@ -19,11 +19,14 @@ namespace WatchFace.Parser.Models.Elements var useAltCoordinates = CurrentAlt != null && state.CurrentTemperature == null; var iconCoordinates = useAltCoordinates ? CurrentAlt : Current; + if (state.CurrentWeather > WeatherCondition.VeryHeavyDownpour || + state.CurrentWeather < WeatherCondition.Unknown) return; + if (iconCoordinates != null) drawer.DrawImage(LoadWeatherImage(state.CurrentWeather), iconCoordinates.X, iconCoordinates.Y); if (CustomIcon != null) - drawer.DrawImage(resources[CustomIcon.ImageIndex + 1], CustomIcon.X, CustomIcon.Y); + drawer.DrawImage(resources[CustomIcon.ImageIndex + (int)state.CurrentWeather], CustomIcon.X, CustomIcon.Y); } private static Bitmap LoadWeatherImage(WeatherCondition weather) diff --git a/WatchFace.Parser/Models/WatchState.cs b/WatchFace.Parser/Models/WatchState.cs index 53e13c2..b004d0a 100644 --- a/WatchFace.Parser/Models/WatchState.cs +++ b/WatchFace.Parser/Models/WatchState.cs @@ -1,4 +1,6 @@ using System; +using Newtonsoft.Json; +using Newtonsoft.Json.Converters; namespace WatchFace.Parser.Models { @@ -12,15 +14,18 @@ namespace WatchFace.Parser.Models public int Distance { get; set; } = 2367; public int? Pulse { get; set; } = 62; + + [JsonConverter(typeof(StringEnumConverter))] + public WeatherCondition CurrentWeather { get; set; } = WeatherCondition.PartlyCloudy; public int? CurrentTemperature { get; set; } = -10; public int? DayTemperature { get; set; } = -15; public int? NightTemperature { get; set; } = -24; public int? TomorrowDayTemperature { get; set; } public int? TomorrowNightTemperature { get; set; } - public WeatherCondition CurrentWeather { get; set; } = WeatherCondition.Cloudy; // https://en.wikipedia.org/wiki/Air_quality_index#Mainland_China - public AirCondition Air { get; set; } = AirCondition.Excellent; + [JsonConverter(typeof(StringEnumConverter))] + public AirCondition AirQuality { get; set; } = AirCondition.Excellent; public int? AirQualityIndex { get; set; } = 15; public int BatteryLevel { get; set; } = 67; diff --git a/WatchFace.Parser/Models/WeatherCondition.cs b/WatchFace.Parser/Models/WeatherCondition.cs index ccee295..2ca60b9 100644 --- a/WatchFace.Parser/Models/WeatherCondition.cs +++ b/WatchFace.Parser/Models/WeatherCondition.cs @@ -2,7 +2,31 @@ { public enum WeatherCondition { - Unknown = 279, - Cloudy = 247 + Unknown, + PartlyCloudy, + CloudyAndRain, + CloudyAndSnow, + Sunny, + Cloudy, + LightRain, + LightSnow, + Rain, + Snow, + HeavySnow, + HeavyRain, + SandStorm, + SnowAndRain, + Fog, + Haze, + Storm, + VeryHeavySnow, + FloatingDust, + Downpour, + Hail, + HailStorm, + HeavyDownpour, + BlowingDust, + Tornado, + VeryHeavyDownpour } } \ No newline at end of file diff --git a/WatchFace.Parser/PreviewGenerator.cs b/WatchFace.Parser/PreviewGenerator.cs index d25bc9b..62deb7c 100644 --- a/WatchFace.Parser/PreviewGenerator.cs +++ b/WatchFace.Parser/PreviewGenerator.cs @@ -1,8 +1,5 @@ -using System; -using System.Collections.Generic; +using System.Collections.Generic; using System.Drawing; -using System.IO; -using BumpKit; using WatchFace.Parser.Interfaces; using WatchFace.Parser.Models; @@ -10,63 +7,23 @@ namespace WatchFace.Parser { public class PreviewGenerator { - public static void CreateGif(List descriptor, Bitmap[] images, Stream outputStream) + public static IEnumerable CreateAnimation(List descriptor, Bitmap[] images, + IEnumerable states) { var previewWatchFace = new Models.Elements.WatchFace(descriptor); - var watchState = new WatchState(); - var time = watchState.Time; - - using (var encoder = new GifEncoder(outputStream)) + foreach (var watchState in states) { - for (var i = 0; i < 10; i++) + using (var image = CreateFrame(previewWatchFace, images, watchState)) { - var num = i + 1; - watchState.BatteryLevel = 100 - (num * 10); - - watchState.Pulse = 60 + num * 2; - watchState.Steps = num * 1000; - watchState.Calories = num * 75; - watchState.Distance = num * 700; - - watchState.Bluetooth = num > 1 && num < 6; - watchState.Unlocked = num > 2 && num < 7; - watchState.Alarm = num > 3 && num < 8; - watchState.DoNotDisturb = num > 4 && num < 9; - - watchState.DayTemperature += 2; - watchState.NightTemperature += 4; - - if (num < 3) - { - watchState.Air = AirCondition.Unknown; - watchState.AirQualityIndex = null; - } - else - { - watchState.Air = (AirCondition) (num - 3); - watchState.AirQualityIndex = (num - 2) * 50 - 25; - } - - if (num < 3) - watchState.CurrentTemperature = null; - else if (num == 3) - watchState.CurrentTemperature = -10; - else - watchState.CurrentTemperature += 6; - - watchState.Time = new DateTime(time.Year, num, num * 2 + 5, i * 2, i * 6, i); - using (var image = CreateFrame(previewWatchFace, images, watchState)) - { - encoder.AddFrame(image, frameDelay: TimeSpan.FromSeconds(1)); - } + yield return image; } } } - public static Image CreateImage(IEnumerable descriptor, Bitmap[] resources) + public static Image CreateImage(IEnumerable descriptor, Bitmap[] images, WatchState state) { var previewWatchFace = new Models.Elements.WatchFace(descriptor); - return CreateFrame(previewWatchFace, resources, new WatchState()); + return CreateFrame(previewWatchFace, images, state); } private static Image CreateFrame(IDrawable watchFace, Bitmap[] resources, WatchState state) diff --git a/WatchFace.Parser/WatchFace.Parser.csproj b/WatchFace.Parser/WatchFace.Parser.csproj index fc360f4..14008da 100644 --- a/WatchFace.Parser/WatchFace.Parser.csproj +++ b/WatchFace.Parser/WatchFace.Parser.csproj @@ -31,19 +31,19 @@ 4 - - ..\packages\Bumpkit.1.0.2\lib\BumpKit.dll - - - ..\packages\Newtonsoft.Json.10.0.3\lib\net40\Newtonsoft.Json.dll + + ..\packages\Newtonsoft.Json.11.0.2\lib\net40\Newtonsoft.Json.dll - ..\packages\NLog.4.4.12\lib\net40\NLog.dll + ..\packages\NLog.4.5.6\lib\net40-client\NLog.dll + + + @@ -173,9 +173,34 @@ - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + - \ No newline at end of file diff --git a/WatchFace.Parser/WeatherIcons/279.png b/WatchFace.Parser/WeatherIcons/0.png similarity index 100% rename from WatchFace.Parser/WeatherIcons/279.png rename to WatchFace.Parser/WeatherIcons/0.png diff --git a/WatchFace.Parser/WeatherIcons/247.png b/WatchFace.Parser/WeatherIcons/1.png similarity index 100% rename from WatchFace.Parser/WeatherIcons/247.png rename to WatchFace.Parser/WeatherIcons/1.png diff --git a/WatchFace.Parser/WeatherIcons/10.png b/WatchFace.Parser/WeatherIcons/10.png new file mode 100644 index 0000000..9199265 Binary files /dev/null and b/WatchFace.Parser/WeatherIcons/10.png differ diff --git a/WatchFace.Parser/WeatherIcons/11.png b/WatchFace.Parser/WeatherIcons/11.png new file mode 100644 index 0000000..8b7492f Binary files /dev/null and b/WatchFace.Parser/WeatherIcons/11.png differ diff --git a/WatchFace.Parser/WeatherIcons/12.png b/WatchFace.Parser/WeatherIcons/12.png new file mode 100644 index 0000000..73b2266 Binary files /dev/null and b/WatchFace.Parser/WeatherIcons/12.png differ diff --git a/WatchFace.Parser/WeatherIcons/13.png b/WatchFace.Parser/WeatherIcons/13.png new file mode 100644 index 0000000..34443b6 Binary files /dev/null and b/WatchFace.Parser/WeatherIcons/13.png differ diff --git a/WatchFace.Parser/WeatherIcons/14.png b/WatchFace.Parser/WeatherIcons/14.png new file mode 100644 index 0000000..0e53f02 Binary files /dev/null and b/WatchFace.Parser/WeatherIcons/14.png differ diff --git a/WatchFace.Parser/WeatherIcons/15.png b/WatchFace.Parser/WeatherIcons/15.png new file mode 100644 index 0000000..d9ac466 Binary files /dev/null and b/WatchFace.Parser/WeatherIcons/15.png differ diff --git a/WatchFace.Parser/WeatherIcons/16.png b/WatchFace.Parser/WeatherIcons/16.png new file mode 100644 index 0000000..876ee2d Binary files /dev/null and b/WatchFace.Parser/WeatherIcons/16.png differ diff --git a/WatchFace.Parser/WeatherIcons/17.png b/WatchFace.Parser/WeatherIcons/17.png new file mode 100644 index 0000000..433ec9d Binary files /dev/null and b/WatchFace.Parser/WeatherIcons/17.png differ diff --git a/WatchFace.Parser/WeatherIcons/18.png b/WatchFace.Parser/WeatherIcons/18.png new file mode 100644 index 0000000..2b9e5fb Binary files /dev/null and b/WatchFace.Parser/WeatherIcons/18.png differ diff --git a/WatchFace.Parser/WeatherIcons/19.png b/WatchFace.Parser/WeatherIcons/19.png new file mode 100644 index 0000000..6610b42 Binary files /dev/null and b/WatchFace.Parser/WeatherIcons/19.png differ diff --git a/WatchFace.Parser/WeatherIcons/2.png b/WatchFace.Parser/WeatherIcons/2.png new file mode 100644 index 0000000..7388f00 Binary files /dev/null and b/WatchFace.Parser/WeatherIcons/2.png differ diff --git a/WatchFace.Parser/WeatherIcons/20.png b/WatchFace.Parser/WeatherIcons/20.png new file mode 100644 index 0000000..f9dd59c Binary files /dev/null and b/WatchFace.Parser/WeatherIcons/20.png differ diff --git a/WatchFace.Parser/WeatherIcons/21.png b/WatchFace.Parser/WeatherIcons/21.png new file mode 100644 index 0000000..661c057 Binary files /dev/null and b/WatchFace.Parser/WeatherIcons/21.png differ diff --git a/WatchFace.Parser/WeatherIcons/22.png b/WatchFace.Parser/WeatherIcons/22.png new file mode 100644 index 0000000..83f35c5 Binary files /dev/null and b/WatchFace.Parser/WeatherIcons/22.png differ diff --git a/WatchFace.Parser/WeatherIcons/23.png b/WatchFace.Parser/WeatherIcons/23.png new file mode 100644 index 0000000..afabb22 Binary files /dev/null and b/WatchFace.Parser/WeatherIcons/23.png differ diff --git a/WatchFace.Parser/WeatherIcons/24.png b/WatchFace.Parser/WeatherIcons/24.png new file mode 100644 index 0000000..6494b91 Binary files /dev/null and b/WatchFace.Parser/WeatherIcons/24.png differ diff --git a/WatchFace.Parser/WeatherIcons/25.png b/WatchFace.Parser/WeatherIcons/25.png new file mode 100644 index 0000000..135f5b4 Binary files /dev/null and b/WatchFace.Parser/WeatherIcons/25.png differ diff --git a/WatchFace.Parser/WeatherIcons/3.png b/WatchFace.Parser/WeatherIcons/3.png new file mode 100644 index 0000000..9fa024c Binary files /dev/null and b/WatchFace.Parser/WeatherIcons/3.png differ diff --git a/WatchFace.Parser/WeatherIcons/4.png b/WatchFace.Parser/WeatherIcons/4.png new file mode 100644 index 0000000..6bdaba1 Binary files /dev/null and b/WatchFace.Parser/WeatherIcons/4.png differ diff --git a/WatchFace.Parser/WeatherIcons/5.png b/WatchFace.Parser/WeatherIcons/5.png new file mode 100644 index 0000000..861ef6e Binary files /dev/null and b/WatchFace.Parser/WeatherIcons/5.png differ diff --git a/WatchFace.Parser/WeatherIcons/6.png b/WatchFace.Parser/WeatherIcons/6.png new file mode 100644 index 0000000..6525e70 Binary files /dev/null and b/WatchFace.Parser/WeatherIcons/6.png differ diff --git a/WatchFace.Parser/WeatherIcons/7.png b/WatchFace.Parser/WeatherIcons/7.png new file mode 100644 index 0000000..1164234 Binary files /dev/null and b/WatchFace.Parser/WeatherIcons/7.png differ diff --git a/WatchFace.Parser/WeatherIcons/8.png b/WatchFace.Parser/WeatherIcons/8.png new file mode 100644 index 0000000..173d588 Binary files /dev/null and b/WatchFace.Parser/WeatherIcons/8.png differ diff --git a/WatchFace.Parser/WeatherIcons/9.png b/WatchFace.Parser/WeatherIcons/9.png new file mode 100644 index 0000000..aa6c0e4 Binary files /dev/null and b/WatchFace.Parser/WeatherIcons/9.png differ diff --git a/WatchFace.Parser/packages.config b/WatchFace.Parser/packages.config index 8df43ff..773939d 100644 --- a/WatchFace.Parser/packages.config +++ b/WatchFace.Parser/packages.config @@ -1,6 +1,5 @@  - - - + + \ No newline at end of file diff --git a/WatchFace/Program.cs b/WatchFace/Program.cs index cdcbd97..301c5bc 100644 --- a/WatchFace/Program.cs +++ b/WatchFace/Program.cs @@ -3,6 +3,8 @@ using System.Collections.Generic; using System.Drawing; using System.Drawing.Imaging; using System.IO; +using System.Reflection; +using BumpKit; using Newtonsoft.Json; using NLog; using NLog.Config; @@ -10,6 +12,7 @@ using NLog.Targets; using Resources; using Resources.Models; using WatchFace.Parser; +using WatchFace.Parser.Models; using WatchFace.Parser.Utils; using Reader = WatchFace.Parser.Reader; using Writer = WatchFace.Parser.Writer; @@ -20,6 +23,7 @@ namespace WatchFace { private const string AppName = "WatchFace"; + private static readonly bool IsRunningOnMono = Type.GetType("Mono.Runtime") != null; private static readonly Logger Logger = LogManager.GetCurrentClassLogger(); private static void Main(string[] args) @@ -107,7 +111,7 @@ namespace WatchFace var imagesDirectory = Path.GetDirectoryName(inputFileName); try { - WriteWatchFace(outputFileName, imagesDirectory, watchFace); + WriteWatchFace(outputDirectory, outputFileName, imagesDirectory, watchFace); } catch (Exception) { @@ -128,13 +132,8 @@ namespace WatchFace var watchFace = ParseResources(reader); if (watchFace == null) return; - Logger.Debug("Generating previews..."); - var preview = PreviewGenerator.CreateImage(reader.Parameters, reader.Images.ToArray()); - preview.Save(Path.Combine(outputDirectory, $"{baseName}_preview.png"), ImageFormat.Png); - using (var gifOutput = File.OpenWrite(Path.Combine(outputDirectory, $"{baseName}_preview.gif"))) - { - PreviewGenerator.CreateGif(reader.Parameters, reader.Images.ToArray(), gifOutput); - } + + GeneratePreviews(reader.Parameters, reader.Images.ToArray(), outputDirectory, baseName); Logger.Debug("Exporting resources to '{0}'", outputDirectory); var reDescriptor = new FileDescriptor {Images = reader.Images}; @@ -192,7 +191,8 @@ namespace WatchFace } if (resDescriptor.ResourcesCount != null && resDescriptor.ResourcesCount.Value != images.Count) - throw new ArgumentException($"The .res-file should contain {resDescriptor.ResourcesCount.Value} images but was loaded {images.Count} images."); + throw new ArgumentException( + $"The .res-file should contain {resDescriptor.ResourcesCount.Value} images but was loaded {images.Count} images."); resDescriptor.Images = images; @@ -218,7 +218,7 @@ namespace WatchFace new Extractor(resDescriptor).Extract(outputDirectory); } - private static void WriteWatchFace(string outputFileName, string imagesDirectory, Parser.WatchFace watchFace) + private static void WriteWatchFace(string outputDirectory, string outputFileName, string imagesDirectory, Parser.WatchFace watchFace) { try { @@ -229,13 +229,8 @@ namespace WatchFace Logger.Trace("Building parameters for watch face..."); var descriptor = ParametersConverter.Build(watchFace); - Logger.Debug("Generating preview..."); - var preview = PreviewGenerator.CreateImage(descriptor, imagesReader.Images.ToArray()); - preview.Save(Path.ChangeExtension(outputFileName, ".png")); - using (var gifOutput = File.OpenWrite(Path.ChangeExtension(outputFileName, ".gif"))) - { - PreviewGenerator.CreateGif(descriptor, imagesReader.Images.ToArray(), gifOutput); - } + var baseFilename = Path.GetFileNameWithoutExtension(outputFileName); + GeneratePreviews(descriptor, imagesReader.Images.ToArray(), outputDirectory, baseFilename); Logger.Debug("Writing watch face to '{0}'", outputFileName); using (var fileStream = File.OpenWrite(outputFileName)) @@ -400,5 +395,109 @@ namespace WatchFace LogManager.Configuration = config; } + + private static void GeneratePreviews(List parameters, Bitmap[] images, string outputDirectory, string baseName) + { + Logger.Debug("Generating previews..."); + + var states = GetPreviewStates(); + var staticPreview = PreviewGenerator.CreateImage(parameters, images, new WatchState()); + staticPreview.Save(Path.Combine(outputDirectory, $"{baseName}_static.png"), ImageFormat.Png); + + var previewImages = PreviewGenerator.CreateAnimation(parameters, images, states); + + if (IsRunningOnMono) + { + var i = 0; + foreach (var previewImage in previewImages) + { + previewImage.Save(Path.Combine(outputDirectory, $"{baseName}_animated_{i}.png"), ImageFormat.Png); + i++; + } + } + else + { + using (var gifOutput = File.OpenWrite(Path.Combine(outputDirectory, $"{baseName}_animated.gif"))) + using (var encoder = new GifEncoder(gifOutput)) + { + foreach (var previewImage in previewImages) + encoder.AddFrame(previewImage, frameDelay: TimeSpan.FromSeconds(1)); + } + } + } + + private static IEnumerable GetPreviewStates() + { + var appPath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); + var previewStatesPath = Path.Combine(appPath, "PreviewStates.json"); + + if (File.Exists(previewStatesPath)) + using (var stream = File.OpenRead(previewStatesPath)) + using (var reader = new StreamReader(stream)) + { + var json = reader.ReadToEnd(); + return JsonConvert.DeserializeObject>(json); + } + + var previewStates = GenerateSampleStates(); + using (var stream = File.OpenWrite(previewStatesPath)) + using (var writer = new StreamWriter(stream)) + { + var json = JsonConvert.SerializeObject(previewStates, Formatting.Indented); + writer.Write(json); + writer.Flush(); + } + + return previewStates; + } + + private static IEnumerable GenerateSampleStates() + { + var time = DateTime.Now; + var states = new List(); + + for (var i = 0; i < 10; i++) + { + var num = i + 1; + var watchState = new WatchState + { + BatteryLevel = 100 - i * 10, + Pulse = 60 + num * 2, + Steps = num * 1000, + Calories = num * 75, + Distance = num * 700, + Bluetooth = num > 1 && num < 6, + Unlocked = num > 2 && num < 7, + Alarm = num > 3 && num < 8, + DoNotDisturb = num > 4 && num < 9, + + DayTemperature = -15 + 2 * i, + NightTemperature = -24 + i * 4, + }; + + if (num < 3) + { + watchState.AirQuality = AirCondition.Unknown; + watchState.AirQualityIndex = null; + + watchState.CurrentWeather = WeatherCondition.Unknown; + watchState.CurrentTemperature = null; + } + else + { + var index = num - 2; + watchState.AirQuality = (AirCondition) index; + watchState.CurrentWeather = (WeatherCondition) index; + + watchState.AirQualityIndex = index * 50 - 25; + watchState.CurrentTemperature = -10 + i * 6; + } + + watchState.Time = new DateTime(time.Year, num, num * 2 + 5, i * 2, i * 6, i); + states.Add(watchState); + } + + return states; + } } } \ No newline at end of file diff --git a/WatchFace/WatchFace.csproj b/WatchFace/WatchFace.csproj index 652baca..ec6d17b 100644 --- a/WatchFace/WatchFace.csproj +++ b/WatchFace/WatchFace.csproj @@ -35,16 +35,24 @@ 4 - - ..\packages\Newtonsoft.Json.10.0.3\lib\net40\Newtonsoft.Json.dll + + ..\packages\Bumpkit.1.0.2\lib\BumpKit.dll + + + + ..\packages\Newtonsoft.Json.11.0.2\lib\net40\Newtonsoft.Json.dll - ..\packages\NLog.4.4.12\lib\net40\NLog.dll + ..\packages\NLog.4.5.6\lib\net40-client\NLog.dll + + + + diff --git a/WatchFace/packages.config b/WatchFace/packages.config index ec8ab8b..e79e7bc 100644 --- a/WatchFace/packages.config +++ b/WatchFace/packages.config @@ -1,6 +1,6 @@  - - - + + + \ No newline at end of file