Added extracting font images from 0.1.0.86 firmware
parent
ac785b0c6a
commit
64beee1574
|
@ -0,0 +1,7 @@
|
|||
namespace FwFonts
|
||||
{
|
||||
public class Constants
|
||||
{
|
||||
public const uint FirmwareBase = 0x8008000;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,74 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using FwFonts.Models;
|
||||
using NLog;
|
||||
|
||||
namespace FwFonts
|
||||
{
|
||||
public class FileReader
|
||||
{
|
||||
private const uint VersionOffset = 0x803BC80;
|
||||
|
||||
private static readonly Dictionary<string, uint> FontOffsets = new Dictionary<string, uint>
|
||||
{
|
||||
["wf1"] = 0x806B848,
|
||||
["wf5"] = 0x806BB70,
|
||||
["font3"] = 0x806BF84,
|
||||
["font2"] = 0x806C388,
|
||||
["font1"] = 0x806C9F4,
|
||||
["wf7_time"] = 0x806CFDC,
|
||||
["wf8_time"] = 0x806D4EC,
|
||||
["wf6"] = 0x806D674,
|
||||
["font4"] = 0x806D7C4,
|
||||
["wf7_wf8_small"] = 0x806DA90,
|
||||
["wf8_big"] = 0x806DD2C
|
||||
};
|
||||
|
||||
private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
|
||||
|
||||
public static FirmweareDescriptor Read(Stream stream)
|
||||
{
|
||||
var binaryReader = new BinaryReader(stream);
|
||||
|
||||
stream.Seek(VersionOffset - Constants.FirmwareBase, SeekOrigin.Begin);
|
||||
|
||||
var version = Encoding.ASCII.GetString(binaryReader.ReadBytes(8));
|
||||
Logger.Debug("Firmware version was read:");
|
||||
Logger.Debug("Version: {0}", version);
|
||||
|
||||
var result = new FirmweareDescriptor {Fonts = new Dictionary<string, FontDescriptor>()};
|
||||
|
||||
foreach (var fontOffset in FontOffsets)
|
||||
{
|
||||
var font = new FontDescriptor
|
||||
{
|
||||
Images = new Dictionary<char, Bitmap>(),
|
||||
Blocks = new List<BlockDescriptor>()
|
||||
};
|
||||
|
||||
var offset = fontOffset.Value - Constants.FirmwareBase;
|
||||
var name = fontOffset.Key;
|
||||
Logger.Debug("Reading font '{0}' from offset 0x{1}", name, offset);
|
||||
BlockDescriptor block;
|
||||
do
|
||||
{
|
||||
stream.Seek(offset, SeekOrigin.Begin);
|
||||
block = BlockDescriptor.ReadFrom(binaryReader);
|
||||
var blockImages = new Reader(stream).ReadBlock(block);
|
||||
|
||||
foreach (var blockImage in blockImages)
|
||||
font.Images.Add(blockImage.Key, blockImage.Value);
|
||||
font.Blocks.Add(block);
|
||||
|
||||
offset = block.NextBlockFileOffset;
|
||||
} while (block.NextBlockOffset > 0);
|
||||
|
||||
result.Fonts[name] = font;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -30,10 +30,25 @@
|
|||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="BumpKit, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Bumpkit.1.0.2\lib\BumpKit.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="NLog, Version=4.0.0.0, Culture=neutral, PublicKeyToken=5120e14c03d0593c, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\NLog.4.4.12\lib\net40\NLog.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Drawing" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Constants.cs" />
|
||||
<Compile Include="GlyphReader.cs" />
|
||||
<Compile Include="Models\FirmweareDescriptor.cs" />
|
||||
<Compile Include="Models\GlyphDescriptor.cs" />
|
||||
<Compile Include="Models\FontDescriptor.cs" />
|
||||
<Compile Include="FileReader.cs" />
|
||||
<Compile Include="Models\BlockDescriptor.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="Reader.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Utils\Utils.csproj">
|
||||
|
@ -41,5 +56,8 @@
|
|||
<Name>Utils</Name>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="packages.config" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
</Project>
|
|
@ -0,0 +1,41 @@
|
|||
using System.Drawing;
|
||||
using System.IO;
|
||||
using BumpKit;
|
||||
using FwFonts.Models;
|
||||
using Utils;
|
||||
|
||||
namespace FwFonts
|
||||
{
|
||||
public class GlyphReader
|
||||
{
|
||||
private readonly Stream _stream;
|
||||
private readonly BinaryReader _reader;
|
||||
|
||||
public GlyphReader(Stream stream)
|
||||
{
|
||||
_stream = stream;
|
||||
_reader = new BinaryReader(stream);
|
||||
}
|
||||
|
||||
public Bitmap Read(GlyphDescriptor glyph)
|
||||
{
|
||||
_stream.Seek(glyph.DataFileOffset, SeekOrigin.Begin);
|
||||
var image = new Bitmap(glyph.Width + glyph.OffsetX, glyph.Height + glyph.OffsetY);
|
||||
using (var context = image.CreateUnsafeContext())
|
||||
{
|
||||
for (var y = glyph.OffsetY; y < image.Height; y++)
|
||||
{
|
||||
var rowBytes = _reader.ReadBytes(glyph.RowLength);
|
||||
var bitReader = new BitReader(rowBytes);
|
||||
for (var x = glyph.OffsetX; x < image.Width; x++)
|
||||
{
|
||||
var pixelValue = bitReader.ReadBits(1);
|
||||
var color = pixelValue == 1 ? Color.Black : Color.FromArgb(0, Color.White);
|
||||
context.SetPixel(x, y, color);
|
||||
}
|
||||
}
|
||||
}
|
||||
return image;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
using System.IO;
|
||||
|
||||
namespace FwFonts.Models
|
||||
{
|
||||
public class BlockDescriptor
|
||||
{
|
||||
public char StartSymbol { get; set; }
|
||||
public char EndSymbol { get; set; }
|
||||
public uint GlyphsOffset { get; set; }
|
||||
public uint NextBlockOffset { get; set; }
|
||||
|
||||
public bool HasNextBlock => NextBlockOffset > 0;
|
||||
public uint NextBlockFileOffset => NextBlockOffset - Constants.FirmwareBase;
|
||||
public uint GlyphsFileOffset => GlyphsOffset - Constants.FirmwareBase;
|
||||
|
||||
public static BlockDescriptor ReadFrom(BinaryReader reader)
|
||||
{
|
||||
return new BlockDescriptor
|
||||
{
|
||||
StartSymbol = (char) reader.ReadUInt16(),
|
||||
EndSymbol = (char) reader.ReadUInt16(),
|
||||
GlyphsOffset = reader.ReadUInt32(),
|
||||
NextBlockOffset = reader.ReadUInt32()
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
using System.Collections.Generic;
|
||||
|
||||
namespace FwFonts.Models
|
||||
{
|
||||
public class FirmweareDescriptor
|
||||
{
|
||||
public string Version { get; set; }
|
||||
public Dictionary<string, FontDescriptor> Fonts { get; set; } = new Dictionary<string, FontDescriptor>();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
|
||||
namespace FwFonts.Models
|
||||
{
|
||||
public class FontDescriptor
|
||||
{
|
||||
public List<BlockDescriptor> Blocks { get; set; } = new List<BlockDescriptor>();
|
||||
public Dictionary<char, Bitmap> Images { get; set; } = new Dictionary<char, Bitmap>();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
using System.IO;
|
||||
|
||||
namespace FwFonts.Models
|
||||
{
|
||||
public class GlyphDescriptor
|
||||
{
|
||||
public byte Width { get; set; }
|
||||
public byte Height { get; set; }
|
||||
public byte OffsetX { get; set; }
|
||||
public byte OffsetY { get; set; }
|
||||
public ushort DrawWidth { get; set; }
|
||||
public ushort Unknown6 { get; set; }
|
||||
public uint DataOffset { get; set; }
|
||||
|
||||
public char Symbol { get; set; }
|
||||
|
||||
public int RowLength => Width % 8 == 0 ? Width / 8 : Width / 8 + 1;
|
||||
public uint DataFileOffset => DataOffset - Constants.FirmwareBase;
|
||||
|
||||
public static GlyphDescriptor ReadFrom(BinaryReader reader, char symbol)
|
||||
{
|
||||
return new GlyphDescriptor
|
||||
{
|
||||
Width = reader.ReadByte(),
|
||||
Height = reader.ReadByte(),
|
||||
OffsetX = reader.ReadByte(),
|
||||
OffsetY = reader.ReadByte(),
|
||||
DrawWidth = reader.ReadUInt16(),
|
||||
Unknown6 = reader.ReadUInt16(),
|
||||
DataOffset = reader.ReadUInt32(),
|
||||
Symbol = symbol
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.IO;
|
||||
using FwFonts.Models;
|
||||
using NLog;
|
||||
|
||||
namespace FwFonts
|
||||
{
|
||||
public class Reader
|
||||
{
|
||||
private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
|
||||
|
||||
private readonly BinaryReader _binaryReader;
|
||||
private readonly Stream _stream;
|
||||
|
||||
public Reader(Stream stream)
|
||||
{
|
||||
_stream = stream;
|
||||
_binaryReader = new BinaryReader(_stream);
|
||||
}
|
||||
|
||||
public Dictionary<char, Bitmap> ReadBlock(BlockDescriptor block)
|
||||
{
|
||||
_stream.Seek(block.GlyphsFileOffset, SeekOrigin.Begin);
|
||||
|
||||
Logger.Trace("Reading block of symbols from '{0}' to '{1}' images...", block.StartSymbol, block.EndSymbol);
|
||||
var glyphs = new List<GlyphDescriptor>(block.EndSymbol - block.StartSymbol);
|
||||
for (var currentChar = block.StartSymbol; currentChar <= block.EndSymbol; currentChar++)
|
||||
{
|
||||
Logger.Trace("Reading descriptor of symbol '{0}'...", currentChar);
|
||||
glyphs.Add(GlyphDescriptor.ReadFrom(_binaryReader, currentChar));
|
||||
}
|
||||
|
||||
var images = new Dictionary<char, Bitmap>(glyphs.Count);
|
||||
foreach (var glyphDescriptor in glyphs)
|
||||
{
|
||||
Logger.Debug("Reading image of symbol '{0}'...", glyphDescriptor.Symbol);
|
||||
images[glyphDescriptor.Symbol] = new GlyphReader(_stream).Read(glyphDescriptor);
|
||||
}
|
||||
|
||||
return images;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="Bumpkit" version="1.0.2" targetFramework="net40" />
|
||||
<package id="NLog" version="4.4.12" targetFramework="net40" />
|
||||
</packages>
|
|
@ -3,6 +3,7 @@ using System.Collections.Generic;
|
|||
using System.Drawing;
|
||||
using System.Drawing.Imaging;
|
||||
using System.IO;
|
||||
using FwFonts.Models;
|
||||
using Newtonsoft.Json;
|
||||
using NLog;
|
||||
using NLog.Config;
|
||||
|
@ -85,6 +86,9 @@ namespace WatchFace
|
|||
case ".latin":
|
||||
UnpackFont(inputFileName);
|
||||
break;
|
||||
case ".fw":
|
||||
UnpackFwFont(inputFileName);
|
||||
break;
|
||||
default:
|
||||
Console.WriteLine("The app doesn't support files with extension {0}.", inputFileExtension);
|
||||
Console.WriteLine("Only 'bin', 'res' and 'json' files are supported at this time.");
|
||||
|
@ -206,6 +210,30 @@ namespace WatchFace
|
|||
}
|
||||
}
|
||||
|
||||
private static void UnpackFwFont(string inputFileName)
|
||||
{
|
||||
var outputDirectory = CreateOutputDirectory(inputFileName);
|
||||
var baseName = Path.GetFileNameWithoutExtension(inputFileName);
|
||||
SetupLogger(Path.Combine(outputDirectory, $"{baseName}.log"));
|
||||
|
||||
FwFonts.Models.FirmweareDescriptor descriptor;
|
||||
using (var stream = File.OpenRead(inputFileName))
|
||||
{
|
||||
descriptor = FwFonts.FileReader.Read(stream);
|
||||
}
|
||||
|
||||
foreach (var font in descriptor.Fonts)
|
||||
{
|
||||
var fontDirectory = Path.Combine(outputDirectory, font.Key);
|
||||
if (!Directory.Exists(fontDirectory)) Directory.CreateDirectory(fontDirectory);
|
||||
|
||||
foreach (var image in font.Value.Images)
|
||||
{
|
||||
image.Value.Save(Path.Combine(fontDirectory, $"0x{(ushort)image.Key:x4}.png"), ImageFormat.Png);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void UnpackFont(string inputFileName)
|
||||
{
|
||||
var outputDirectory = CreateOutputDirectory(inputFileName);
|
||||
|
|
|
@ -62,6 +62,10 @@
|
|||
<Project>{390eaf2d-9fa8-4dc1-8d4f-ea565ad3c682}</Project>
|
||||
<Name>Fonts</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\FwFonts\FwFonts.csproj">
|
||||
<Project>{e50e8437-0511-4a94-808a-ad5f3105d060}</Project>
|
||||
<Name>FwFonts</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\Resources\Resources.csproj">
|
||||
<Project>{edd55d5d-9e80-451b-ac8a-0746ba6dc6e9}</Project>
|
||||
<Name>Resources</Name>
|
||||
|
|
Loading…
Reference in New Issue