├── OpenFont
├── Tables.Others
│ ├── Merge.cs
│ ├── LinearThreashold.cs
│ ├── HorizontalDeviceMetrics.cs
│ ├── VerticalDeviceMetrics.cs
│ └── VerticalMetrics.cs
├── Tables.Variations
│ ├── VVar.cs
│ ├── CVar.cs
│ ├── Common.ItemVariationStore.cs
│ ├── AVar.cs
│ └── HVar.cs
├── OpenFont.csproj
├── TrueTypeInterperter
│ └── InvalidFontException.cs
├── README.MD
├── Bounds.cs
├── Tables
│ ├── TableEntryCollection.cs
│ ├── TableHeader.cs
│ ├── TableEntry.cs
│ ├── HorizontalHeader.cs
│ ├── MaxProfile.cs
│ ├── HorizontalMetrics.cs
│ ├── Utils.cs
│ ├── NameEntry.cs
│ └── Head.cs
├── Tables.AdvancedLayout
│ ├── IGlyphIndexList.cs
│ ├── COLR.cs
│ ├── ScriptList.cs
│ ├── AttachmentListTable.cs
│ ├── CPAL.cs
│ ├── CoverageTable.cs
│ └── FeatureList.cs
├── Tables.BitmapAndSvgFonts
│ ├── BitmapFontGlyphSource.cs
│ ├── EBSC.cs
│ ├── EBDT.cs
│ ├── CBDT.cs
│ ├── CBLC.cs
│ ├── EBLC.cs
│ └── SvgTable.cs
├── Tables.TrueType
│ ├── Cvt_Programs.cs
│ ├── GlyphLocations.cs
│ └── Gasp.cs
├── AdditionalInfo
│ ├── OS2_IBMFontClassParameters.cs
│ ├── MacPostFormat1.cs
│ └── Languages.cs
├── Geometry.cs
├── PreviewFontInfo.cs
├── ByteOrderSwappingBinaryReader.cs
├── Tables.CFF
│ └── CFFTable.cs
└── Typeface_TrimableExtensions.cs
├── samples
├── result.png
└── test.in.html
├── Schwabra
├── Result.cs
├── Station.cs
├── ElectionContext.cs
├── Schwabra.csproj
├── Migrations
│ ├── InitialCreate.cs
│ ├── ElectionContextModelSnapshot.cs
│ └── InitialCreate.Designer.cs
└── Program.cs
├── Izbirkom21
├── Izbirkom21.csproj
├── Trash.cs
├── FixedContentMorpher.cs
└── FontReplacer.cs
├── LICENSE
├── izbirkom21.sln
├── README.md
└── .gitignore
/OpenFont/Tables.Others/Merge.cs:
--------------------------------------------------------------------------------
1 | //TODO: implement this
--------------------------------------------------------------------------------
/OpenFont/Tables.Others/LinearThreashold.cs:
--------------------------------------------------------------------------------
1 | //TODO: implement this
--------------------------------------------------------------------------------
/samples/result.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ulex/izbirkom21/HEAD/samples/result.png
--------------------------------------------------------------------------------
/samples/test.in.html:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ulex/izbirkom21/HEAD/samples/test.in.html
--------------------------------------------------------------------------------
/OpenFont/Tables.Variations/VVar.cs:
--------------------------------------------------------------------------------
1 | //TODO: implement this
2 | //https://docs.microsoft.com/en-us/typography/opentype/spec/vvar
--------------------------------------------------------------------------------
/OpenFont/OpenFont.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net5.0
5 | True
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/Schwabra/Result.cs:
--------------------------------------------------------------------------------
1 | namespace Schwabra
2 | {
3 | public class Result
4 | {
5 | public int id { get; set; }
6 | public int num { get; set; }
7 | public string title { get; set; }
8 | public int value { get; set; }
9 | public double? value_percent { get; set; }
10 | }
11 | }
--------------------------------------------------------------------------------
/Schwabra/Station.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 |
3 | namespace Schwabra
4 | {
5 | public class Station
6 | {
7 | public int id { get; set; }
8 | public string name { get; set; }
9 | public string filename { get; set; }
10 | public string path { get; set; }
11 | public List rows { get; set; } = new();
12 | }
13 | }
--------------------------------------------------------------------------------
/Izbirkom21/Izbirkom21.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Exe
5 | net5.0
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/Schwabra/ElectionContext.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.EntityFrameworkCore;
2 |
3 | namespace Schwabra
4 | {
5 | public class ElectionContext : DbContext
6 | {
7 | public DbSet station { get; set; }
8 | public DbSet result { get; set; }
9 |
10 | public string DbPath { get; }
11 |
12 | public ElectionContext() : this("election.sqlite3")
13 | {
14 | }
15 |
16 | public ElectionContext(string path)
17 | {
18 | DbPath = path;
19 | }
20 | protected override void OnConfiguring(DbContextOptionsBuilder options)
21 | => options.UseSqlite($"Data Source={DbPath}");
22 | }
23 | }
--------------------------------------------------------------------------------
/OpenFont/TrueTypeInterperter/InvalidFontException.cs:
--------------------------------------------------------------------------------
1 | //MIT, 2015, Michael Popoloski's SharpFont
2 |
3 | using System;
4 |
5 | namespace Typography.OpenFont
6 | {
7 |
8 | class InvalidFontException : Exception
9 | {
10 | public InvalidFontException() { }
11 | public InvalidFontException(string msg) : base(msg) { }
12 | }
13 | class InvalidTrueTypeFontException : InvalidFontException
14 | {
15 | public InvalidTrueTypeFontException() { }
16 | ///
17 | /// Initializes a new instance of the class.
18 | ///
19 | public InvalidTrueTypeFontException(string msg) : base(msg) { }
20 | }
21 |
22 | }
23 |
--------------------------------------------------------------------------------
/OpenFont/Tables.Variations/CVar.cs:
--------------------------------------------------------------------------------
1 | //MIT, 2019-present, WinterDev
2 | using System;
3 | using System.IO;
4 |
5 | namespace Typography.OpenFont.Tables
6 | {
7 | //https://docs.microsoft.com/en-us/typography/opentype/spec/cvar
8 |
9 | ///
10 | /// cvar — CVT Variations Table
11 | ///
12 | class CVar : TableEntry
13 | {
14 | public const string _N = "cvar";
15 | public override string Name => _N;
16 | public CVar()
17 | {
18 | //The control value table (CVT) variations table is used in variable fonts to provide variation data for CVT values.
19 | //For a general overview of OpenType Font Variations
20 |
21 |
22 | }
23 | protected override void ReadContentFrom(BinaryReader reader)
24 | {
25 |
26 | }
27 | }
28 | }
--------------------------------------------------------------------------------
/Schwabra/Schwabra.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Exe
5 | net5.0
6 |
7 |
8 |
9 |
10 | runtime; build; native; contentfiles; analyzers; buildtransitive
11 | all
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/OpenFont/README.MD:
--------------------------------------------------------------------------------
1 | Typography.OpenFont
2 | ---
3 |
4 | This module is about reading
5 | 1. Open Font Format (.ttf, .otf, .ttc, .otc)
6 | 2. Web Open Font Format (.woff, .woff2)
7 |
8 |
9 | References:
10 |
11 | ISO/IEC 14496-22:2015, Open Font Format, http://www.iso.org/iso/home/store/catalogue_ics/catalogue_detail_ics.htm?csnumber=66391
12 |
13 | Microsoft OpenType Specification, https://www.microsoft.com/en-us/Typography/OpenTypeSpecification.aspx
14 |
15 | The Compact Font Format Specification, Technical Note #5176, Version 1, 4 December 2003, https://typekit.files.wordpress.com/2010/12/5176.cff.pdf
16 |
17 | The Type2 Charstring Format, Technical Note #517716 March 2000, Adobe, https://www.adobe.com/content/dam/acom/en/devnet/font/pdfs/5177.Type2.pdf
18 |
19 | Type1 Font Format, Adobe, https://www.adobe.com/content/dam/acom/en/devnet/font/pdfs/T1_SPEC.pdf
20 |
21 | WOFF 1.0, https://www.w3.org/TR/2012/REC-WOFF-20121213/
22 |
23 | WOFF 2.0, https://www.w3.org/TR/WOFF2/
--------------------------------------------------------------------------------
/OpenFont/Bounds.cs:
--------------------------------------------------------------------------------
1 | //Apache2, 2017-present, WinterDev
2 | //Apache2, 2014-2016, Samuel Carlsson, WinterDev
3 |
4 | namespace Typography.OpenFont
5 | {
6 | ///
7 | /// original glyph bounds
8 | ///
9 | public readonly struct Bounds
10 | {
11 |
12 | //TODO: will be changed to => public readonly struct Bounds
13 |
14 | public static readonly Bounds Zero = new Bounds(0, 0, 0, 0);
15 | public Bounds(short xmin, short ymin, short xmax, short ymax)
16 | {
17 | XMin = xmin;
18 | YMin = ymin;
19 | XMax = xmax;
20 | YMax = ymax;
21 | }
22 |
23 | public short XMin { get; }
24 | public short YMin { get; }
25 | public short XMax { get; }
26 | public short YMax { get; }
27 | #if DEBUG
28 | public override string ToString()
29 | {
30 | return "(" + XMin + "," + YMin + "," + XMax + "," + YMax + ")";
31 | }
32 | #endif
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/OpenFont/Tables/TableEntryCollection.cs:
--------------------------------------------------------------------------------
1 | //Apache2, 2017-present, WinterDev
2 | //Apache2, 2014-2016, Samuel Carlsson, WinterDev
3 |
4 | using System.Collections.Generic;
5 | namespace Typography.OpenFont.Tables
6 | {
7 | class TableEntryCollection
8 | {
9 | readonly Dictionary _tables = new Dictionary();
10 | public TableEntryCollection() { }
11 |
12 | public void AddEntry(TableEntry en) => _tables.Add(en.Name, en);
13 |
14 | public bool TryGetTable(string tableName, out TableEntry entry) => _tables.TryGetValue(tableName, out entry);
15 |
16 | public void ReplaceTable(TableEntry table) => _tables[table.Name] = table;
17 |
18 | public TableHeader[] CloneTableHeaders()
19 | {
20 | TableHeader[] clones = new TableHeader[_tables.Count];
21 | int i = 0;
22 | foreach (TableEntry en in _tables.Values)
23 | {
24 | clones[i] = en.Header.Clone();
25 | i++;
26 | }
27 | return clones;
28 | }
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2021 Alexander Ulitin
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/OpenFont/Tables.AdvancedLayout/IGlyphIndexList.cs:
--------------------------------------------------------------------------------
1 | //Apache2, 2016-present, WinterDev
2 |
3 |
4 | namespace Typography.OpenFont.Tables
5 | {
6 | ///
7 | /// replaceable glyph index list
8 | ///
9 | public interface IGlyphIndexList
10 | {
11 | int Count { get; }
12 | ushort this[int index] { get; }
13 |
14 | ///
15 | /// remove:add_new 1:1
16 | ///
17 | ///
18 | ///
19 | void Replace(int index, ushort newGlyphIndex);
20 | ///
21 | /// remove:add_new >=1:1
22 | ///
23 | ///
24 | ///
25 | ///
26 | void Replace(int index, int removeLen, ushort newGlyphIndex);
27 | ///
28 | /// remove: add_new 1:>=1
29 | ///
30 | ///
31 | ///
32 | void Replace(int index, ushort[] newGlyphIndices);
33 | }
34 |
35 | }
36 |
--------------------------------------------------------------------------------
/Izbirkom21/Trash.cs:
--------------------------------------------------------------------------------
1 | using ExCSS;
2 | using HtmlAgilityPack;
3 |
4 | namespace Izbirkom21
5 | {
6 | public static class Trash
7 | {
8 | public static void RemoveTrashNodes(HtmlDocument htmlDocument)
9 | {
10 | // remove trash nodes
11 | foreach (var span in htmlDocument.DocumentNode.SelectNodes("//span"))
12 | {
13 | var style = span.GetAttributeValue("style", "");
14 | if (string.IsNullOrEmpty(style)) continue;
15 | if (IsTrashStyle("* {" + style + "}"))
16 | {
17 | span.Remove();
18 | }
19 | }
20 | }
21 |
22 | public static bool IsTrashStyle(string stylesheetStr)
23 | {
24 | var stylesheetParser = new StylesheetParser();
25 | var stylesheet = stylesheetParser.Parse(stylesheetStr);
26 | foreach (var styleRule in stylesheet.StyleRules)
27 | {
28 | var style = styleRule.Style;
29 | if (IsTrashStyle(style)) return true;
30 | }
31 |
32 | return false;
33 | }
34 |
35 | public static bool IsTrashStyle(StyleDeclaration style)
36 | {
37 | return style.Position == "absolute" || style.Display == "none" || style.FontSize == "0" ||
38 | style.Color == "white" || style.Overflow == "hidden";
39 | }
40 | }
41 | }
--------------------------------------------------------------------------------
/OpenFont/Tables/TableHeader.cs:
--------------------------------------------------------------------------------
1 | //Apache2, 2017-present, WinterDev
2 | //Apache2, 2014-2016, Samuel Carlsson, WinterDev
3 |
4 | namespace Typography.OpenFont.Tables
5 | {
6 | class TableHeader
7 | {
8 | readonly uint _tag;
9 |
10 | public TableHeader(uint tag, uint checkSum, uint offset, uint len)
11 | {
12 | _tag = tag;
13 | CheckSum = checkSum;
14 | Offset = offset;
15 | Length = len;
16 | Tag = Utils.TagToString(_tag);
17 | }
18 | public TableHeader(string tag, uint checkSum, uint offset, uint len)
19 | {
20 | _tag = 0;
21 | CheckSum = checkSum;
22 | Offset = offset;
23 | Length = len;
24 | Tag = tag;
25 | }
26 | //
27 | public string Tag { get; }
28 | public uint Offset { get; }
29 | public uint CheckSum { get; }
30 | public uint Length { get; }
31 |
32 | public TableHeader Clone() => (_tag != 0) ? new TableHeader(_tag, CheckSum, Offset, Length) : new TableHeader(Tag, CheckSum, Offset, Length);
33 | #if DEBUG
34 | public override string ToString()
35 | {
36 | return "{" + Tag + "}";
37 | }
38 | #endif
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/OpenFont/Tables.BitmapAndSvgFonts/BitmapFontGlyphSource.cs:
--------------------------------------------------------------------------------
1 | //MIT, 2019-present, WinterDev
2 | using System;
3 |
4 | namespace Typography.OpenFont.Tables
5 | {
6 | class BitmapFontGlyphSource
7 | {
8 | readonly CBLC _cblc; //bitmap locator
9 | CBDT _cbdt;
10 | public BitmapFontGlyphSource(CBLC cblc) => _cblc = cblc;
11 |
12 | ///
13 | /// load new bitmap embeded data
14 | ///
15 | ///
16 | public void LoadCBDT(CBDT cbdt) => _cbdt = cbdt;
17 |
18 | ///
19 | /// clear and remove existing bitmap embeded data
20 | ///
21 | public void UnloadCBDT()
22 | {
23 | if (_cbdt != null)
24 | {
25 | _cbdt.RemoveOldMemoryStreamAndReaders();
26 | _cbdt = null;
27 | }
28 | }
29 |
30 | public void CopyBitmapContent(Glyph glyph, System.IO.Stream outputStream) => _cbdt.CopyBitmapContent(glyph, outputStream);
31 |
32 | public Glyph[] BuildGlyphList()
33 | {
34 | Glyph[] glyphs = _cblc.BuildGlyphList();
35 | for (int i = 0; i < glyphs.Length; ++i)
36 | {
37 | _cbdt.FillGlyphInfo(glyphs[i]);
38 | }
39 | return glyphs;
40 | }
41 | }
42 | }
--------------------------------------------------------------------------------
/OpenFont/Tables.BitmapAndSvgFonts/EBSC.cs:
--------------------------------------------------------------------------------
1 | //MIT, 2019-present, WinterDev
2 | using System;
3 | using System.IO;
4 |
5 | namespace Typography.OpenFont.Tables
6 | {
7 |
8 | //from
9 | //https://docs.microsoft.com/en-us/typography/opentype/spec/ebsc
10 |
11 | //The EBSC table provides a mechanism for describing embedded bitmaps
12 | //which are created by scaling other embedded bitmaps.
13 | //While this is the sort of thing that outline font technologies were invented to avoid,
14 | //there are cases (small sizes of Kanji, for example)
15 | //where scaling a bitmap produces a more legible font
16 | //than scan-converting an outline.
17 |
18 | //For this reason the EBSC table allows a font to define a bitmap strike
19 | //as a scaled version of another strike.
20 |
21 | //The EBSC table is used together with the EBDT table,
22 | //which provides embedded monochrome or grayscale bitmap data,
23 | //and the EBLC table, which provides embedded bitmap locators.
24 |
25 |
26 | ///
27 | /// EBSC — Embedded Bitmap Scaling Table
28 | ///
29 | class EBSC : TableEntry
30 | {
31 | public const string _N = "EBSC";
32 | public override string Name => _N;
33 |
34 | protected override void ReadContentFrom(BinaryReader reader)
35 | {
36 |
37 | }
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/OpenFont/Tables.TrueType/Cvt_Programs.cs:
--------------------------------------------------------------------------------
1 | //MIT, 2015-2016, Michael Popoloski, WinterDev
2 |
3 | using System.IO;
4 | namespace Typography.OpenFont.Tables
5 | {
6 |
7 | class CvtTable : TableEntry
8 | {
9 | public const string _N = "cvt ";//need 4 chars//***
10 | public override string Name => _N;
11 |
12 | //
13 |
14 | ///
15 | /// control value in font unit
16 | ///
17 | internal int[] _controlValues;
18 | protected override void ReadContentFrom(BinaryReader reader)
19 | {
20 | int nelems = (int)(this.TableLength / sizeof(short));
21 | var results = new int[nelems];
22 | for (int i = 0; i < nelems; i++)
23 | {
24 | results[i] = reader.ReadInt16();
25 | }
26 | _controlValues = results;
27 | }
28 | }
29 | class PrepTable : TableEntry
30 | {
31 | public const string _N = "prep";
32 | public override string Name => _N;
33 | //
34 |
35 | internal byte[] _programBuffer;
36 | //
37 | protected override void ReadContentFrom(BinaryReader reader)
38 | {
39 | _programBuffer = reader.ReadBytes((int)this.TableLength);
40 | }
41 | }
42 | class FpgmTable : TableEntry
43 | {
44 | public const string _N = "fpgm";
45 | public override string Name => _N;
46 | //
47 |
48 | internal byte[] _programBuffer;
49 | protected override void ReadContentFrom(BinaryReader reader)
50 | {
51 | _programBuffer = reader.ReadBytes((int)this.TableLength);
52 | }
53 | }
54 | }
--------------------------------------------------------------------------------
/Izbirkom21/FixedContentMorpher.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text.RegularExpressions;
5 | using ExCSS;
6 | using HtmlAgilityPack;
7 |
8 | namespace Izbirkom21
9 | {
10 | public class FixedContentMorpher
11 | {
12 | // css class name -> replace text
13 | Dictionary> _classToMorpher = new();
14 |
15 | public void VisitStyleRule(IStyleRule styleRule)
16 | {
17 | var content = styleRule.Style.Content;
18 | var isTrashStyle = Trash.IsTrashStyle(styleRule.Style);
19 | if (!string.IsNullOrEmpty(content) || isTrashStyle)
20 | {
21 | var toReplace = isTrashStyle ? "" : content.Trim('"');
22 | foreach (Match match in Regex.Matches(styleRule.SelectorText, "\\.([\\w_]+)"))
23 | {
24 | var className = match.Groups[0].Value.Trim('.');
25 | if (className.Length <= 7) // 🦄
26 | {
27 | _classToMorpher.Add(className, _ => toReplace);
28 | }
29 | }
30 | }
31 | }
32 |
33 | public void ReplaceFixedContent(HtmlDocument htmlDocument, FontReplacer fonts)
34 | {
35 | // modify content (reverse to process nested first)
36 | foreach (var node in htmlDocument.DocumentNode.SelectNodes("//span|//b|//td").Reverse())
37 | {
38 | var cls = node.GetAttributeValue("class", "");
39 | if (_classToMorpher.TryGetValue(cls, out var replaceTo))
40 | {
41 | node.InnerHtml = replaceTo(node.InnerText);
42 | node.Attributes.Remove("class");
43 | }
44 |
45 | // custom fonts
46 | fonts.TranslateNode(cls, node);
47 | }
48 | }
49 | }
50 | }
--------------------------------------------------------------------------------
/OpenFont/AdditionalInfo/OS2_IBMFontClassParameters.cs:
--------------------------------------------------------------------------------
1 | //Apache2, 2017-present, WinterDev
2 | //https://www.microsoft.com/typography/otspec/ibmfc.htm
3 |
4 | namespace Typography.OpenFont
5 | {
6 |
7 | //This section defines the IBM Font Class
8 | //and the IBM Font Subclass parameter values
9 | //to be used in the classification of font designs by the font designer or supplier.
10 | //
11 | //This information is stored in the sFamilyClass field of a font's OS/2 table.
12 |
13 |
14 | [System.Flags]
15 | enum IBMFontClassParametersKind
16 | {
17 | No_Classification = 0 << 8,
18 | //
19 | //class id 1, OldStyle Serifs
20 | //
21 | Class1 = 1 << 8,
22 | OldStyle_Serifs = Class1,
23 | Class1_No_Classification = Class1 | 0,
24 | Class1_IBM_Rounded_Legibility = Class1 | 1,
25 | Class1_Garalde = Class1 | 2,
26 | Class1_Venetian = Class1 | 3,
27 | Class1_Modified_Venetian = Class1 | 4,
28 | Class1_Dutch_Modern = Class1 | 5,
29 | Class1_Dutch_Traditional = Class1 | 6,
30 | Class1_Comtemporary = Class1 | 7,
31 | Class1_Calligraphic = Class1 | 8,
32 | //subclass 9-14 -> (reserved for future use)
33 | Class1_Miscellaneous = Class1 | 15,
34 | //
35 | //class id 2, Transitional Serifs
36 | //
37 | Class2 = 2 << 8,
38 | Class2_No_Classification = Class2 | 0,
39 | Class2_Direct_Line = Class2 | 1,
40 | Class2_Script = Class2 | 2,
41 | //subclass 3-14 -> (reserved for future use)
42 | Class2_Miscellaneous = Class2 | 15,
43 | //
44 | //class id 3, Modern Serifs
45 | //
46 | //TODO... add more...
47 |
48 |
49 | }
50 |
51 | }
--------------------------------------------------------------------------------
/OpenFont/Tables/TableEntry.cs:
--------------------------------------------------------------------------------
1 | //Apache2, 2017-present, WinterDev
2 | //Apache2, 2014-2016, Samuel Carlsson, WinterDev
3 |
4 | using System;
5 | using System.IO;
6 | namespace Typography.OpenFont.Tables
7 | {
8 | ///
9 | /// this is base class of all 'top' font table
10 | ///
11 | public abstract class TableEntry
12 | {
13 | public TableEntry()
14 | {
15 | }
16 | internal TableHeader Header { get; set; }
17 | protected abstract void ReadContentFrom(BinaryReader reader);
18 | public abstract string Name { get; }
19 | internal void LoadDataFrom(BinaryReader reader)
20 | {
21 | //ensure that we always start at the correct offset***
22 | reader.BaseStream.Seek(this.Header.Offset, SeekOrigin.Begin);
23 | ReadContentFrom(reader);
24 | }
25 | public uint TableLength => this.Header.Length;
26 |
27 | }
28 | class UnreadTableEntry : TableEntry
29 | {
30 | public UnreadTableEntry(TableHeader header)
31 | {
32 | this.Header = header;
33 | }
34 | public override string Name => this.Header.Tag;
35 | //
36 | protected sealed override void ReadContentFrom(BinaryReader reader)
37 | {
38 | //intend ***
39 | throw new NotImplementedException();
40 | }
41 |
42 | public bool HasCustomContentReader { get; protected set; }
43 | public virtual T CreateTableEntry(BinaryReader reader, T expectedResult)
44 | where T : TableEntry
45 | {
46 | throw new NotImplementedException();
47 | }
48 | #if DEBUG
49 | public override string ToString()
50 | {
51 | return this.Name;
52 | }
53 | #endif
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/izbirkom21.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio Version 17
4 | VisualStudioVersion = 17.0.31710.8
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Izbirkom21", "Izbirkom21\Izbirkom21.csproj", "{406F57B4-06F9-49EB-B836-9596641E3220}"
7 | EndProject
8 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OpenFont", "OpenFont\OpenFont.csproj", "{042710D0-13D9-4C49-89F3-6B6D59F107D6}"
9 | EndProject
10 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Schwabra", "Schwabra\Schwabra.csproj", "{94E4C9B4-71FD-4135-B333-B9949E5B0B7D}"
11 | EndProject
12 | Global
13 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
14 | Debug|Any CPU = Debug|Any CPU
15 | Release|Any CPU = Release|Any CPU
16 | EndGlobalSection
17 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
18 | {406F57B4-06F9-49EB-B836-9596641E3220}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
19 | {406F57B4-06F9-49EB-B836-9596641E3220}.Debug|Any CPU.Build.0 = Debug|Any CPU
20 | {406F57B4-06F9-49EB-B836-9596641E3220}.Release|Any CPU.ActiveCfg = Release|Any CPU
21 | {406F57B4-06F9-49EB-B836-9596641E3220}.Release|Any CPU.Build.0 = Release|Any CPU
22 | {042710D0-13D9-4C49-89F3-6B6D59F107D6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
23 | {042710D0-13D9-4C49-89F3-6B6D59F107D6}.Debug|Any CPU.Build.0 = Debug|Any CPU
24 | {042710D0-13D9-4C49-89F3-6B6D59F107D6}.Release|Any CPU.ActiveCfg = Release|Any CPU
25 | {042710D0-13D9-4C49-89F3-6B6D59F107D6}.Release|Any CPU.Build.0 = Release|Any CPU
26 | {94E4C9B4-71FD-4135-B333-B9949E5B0B7D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
27 | {94E4C9B4-71FD-4135-B333-B9949E5B0B7D}.Debug|Any CPU.Build.0 = Debug|Any CPU
28 | {94E4C9B4-71FD-4135-B333-B9949E5B0B7D}.Release|Any CPU.ActiveCfg = Release|Any CPU
29 | {94E4C9B4-71FD-4135-B333-B9949E5B0B7D}.Release|Any CPU.Build.0 = Release|Any CPU
30 | EndGlobalSection
31 | GlobalSection(SolutionProperties) = preSolution
32 | HideSolutionNode = FALSE
33 | EndGlobalSection
34 | GlobalSection(ExtensibilityGlobals) = postSolution
35 | SolutionGuid = {95430CAB-205F-4820-9138-1A9593AD0D55}
36 | EndGlobalSection
37 | EndGlobal
38 |
--------------------------------------------------------------------------------
/OpenFont/Geometry.cs:
--------------------------------------------------------------------------------
1 | //MIT, 2015, Michael Popoloski's SharpFont,
2 | //MIT, 2016-present, WinterDev
3 |
4 |
5 | using System.Numerics;
6 | namespace Typography.OpenFont
7 | {
8 | [System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Sequential)]
9 | public struct GlyphPointF
10 | {
11 | //from https://docs.microsoft.com/en-us/typography/opentype/spec/glyf
12 | //'point' of the glyph contour.
13 | //eg. ... In the glyf table, the position of a point ...
14 | // ... the point is on the curve; otherwise, it is off the curve....
15 |
16 | internal Vector2 P;
17 | internal bool onCurve;
18 |
19 | public GlyphPointF(float x, float y, bool onCurve)
20 | {
21 | P = new Vector2(x, y);
22 | this.onCurve = onCurve;
23 | }
24 | public GlyphPointF(Vector2 position, bool onCurve)
25 | {
26 | P = position;
27 | this.onCurve = onCurve;
28 | }
29 | public float X => this.P.X;
30 | public float Y => this.P.Y;
31 |
32 | public static GlyphPointF operator *(GlyphPointF p, float n)
33 | {
34 | return new GlyphPointF(p.P * n, p.onCurve);
35 | }
36 |
37 | //-----------------------------------------
38 |
39 | internal GlyphPointF Offset(short dx, short dy) { return new GlyphPointF(new Vector2(P.X + dx, P.Y + dy), onCurve); }
40 |
41 | internal void ApplyScale(float scale)
42 | {
43 | P *= scale;
44 | }
45 | internal void ApplyScaleOnlyOnXAxis(float scale)
46 | {
47 | P = new Vector2(P.X * scale, P.Y);
48 | }
49 |
50 | internal void UpdateX(float x)
51 | {
52 | this.P.X = x;
53 | }
54 | internal void UpdateY(float y)
55 | {
56 | this.P.Y = y;
57 | }
58 | internal void OffsetY(float dy)
59 | {
60 | this.P.Y += dy;
61 | }
62 | internal void OffsetX(float dx)
63 | {
64 | this.P.X += dx;
65 | }
66 | #if DEBUG
67 | internal bool dbugIsEqualsWith(GlyphPointF another)
68 | {
69 | return this.P == another.P && this.onCurve == another.onCurve;
70 | }
71 | public override string ToString() { return P.ToString() + " " + onCurve.ToString(); }
72 | #endif
73 | }
74 |
75 |
76 | }
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | Деобфускатор результатов выборов 2021
2 | ==============
3 |
4 | На вход требуется сохранённая html страница с сайта izbirkom.ru.
5 | В выходной файл запишется версия страницы без интерактивных элементов и стилей в удобном для дальнейшего анализа виде.
6 |
7 | Обфускатор может работать в полностью оффлайн режиме, если у него есть доступ к шрифтам, которые имеются в количестве 100 штук на сайте избиркома. Они кешируются в папку `fonts_cache`. Если шрифт с необходимым именем уже есть, то загружаться снова он не будет.
8 |
9 |
10 | Для запуска требуется [.net 5.0 SDK](https://dotnet.microsoft.com/download), должно работать на Windows/Linux/Mac.
11 |
12 | 
13 |
14 |
15 | [Исходная страница](https://raw.githubusercontent.com/ulex/izbirkom21/master/samples/test.in.html) была получена с помощью команды
16 | ```
17 | curl -A 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:92.0) Gecko/20100101 Firefox/92.0' 'http://www.crimea.vybory.izbirkom.ru/region/izbirkom?action=show&root=1000050&tvd=100100225883448&vrn=100100225883172&prver=0&pronetvd=null®ion=19&sub_region=19&type=463&report_mode=null' > test.in.html
18 | ```
19 | [Пример деобфусцированного результата](https://raw.githubusercontent.com/ulex/izbirkom21/master/samples/test.out.html), который был получен с помощью команды
20 | ```
21 | dotnet run --project izbirkom21 samples/test.in.html samples/test.out.html
22 | ```
23 |
24 | Работа в пакетном режиме
25 | ----
26 |
27 | Теперь можно запускать приложение на директориях. В этом случае, будут пытаться деобфусцироваться все файлы, которые есть в параметре 1 и записываться в директорию, указанную в параметре 2. Этот режим существенно быстрее обработки файлов по одному и на моём оборудовании обрабатывает примерно 40 файлов в секунду.
28 | ```
29 | dotnet run --configuration Release --project izbirkom21 samples outDirectory
30 | ```
31 |
32 | Сырые данные
33 | ----
34 |
35 | Пользователь @illusionofchaos предлагает уже загруженные данные и шрифты с ЦИК по федеральному избирательному округу:
36 | https://github.com/illusionofchaos/IzbirkomRipper/releases/tag/0.0.1
37 |
38 | Достоверность данных я не гарантирую
39 |
40 |
41 | Используемые зависимости
42 | ----
43 |
44 | https://github.com/LayoutFarm/Typography
45 | MIT
46 |
47 | https://github.com/zzzprojects/html-agility-pack/blob/master/LICENSE
48 | MIT
49 |
50 | https://github.com/TylerBrinks/ExCSS
51 | MIT
52 |
53 |
--------------------------------------------------------------------------------
/OpenFont/Tables.AdvancedLayout/COLR.cs:
--------------------------------------------------------------------------------
1 | //Apache2, 2017-present Sam Hocevar , WinterDev
2 |
3 | using System;
4 | using System.Collections.Generic;
5 | using System.IO;
6 |
7 | namespace Typography.OpenFont.Tables
8 | {
9 | public class COLR : TableEntry
10 | {
11 | public const string _N = "COLR";
12 | public override string Name => _N;
13 |
14 | // Read the COLR table
15 | // https://docs.microsoft.com/en-us/typography/opentype/spec/colr
16 | protected override void ReadContentFrom(BinaryReader reader)
17 | {
18 | long offset = reader.BaseStream.Position;
19 |
20 | //Type Name Description
21 | //uint16 version Table version number(starts at 0).
22 | //uint16 numBaseGlyphRecords Number of Base Glyph Records.
23 | //Offset32 baseGlyphRecordsOffset Offset(from beginning of COLR table) to Base Glyph records.
24 | //Offset32 layerRecordsOffset Offset(from beginning of COLR table) to Layer Records.
25 | //uint16 numLayerRecords Number of Layer Records.
26 |
27 |
28 | ushort version = reader.ReadUInt16();
29 | ushort numBaseGlyphRecords = reader.ReadUInt16();
30 | uint baseGlyphRecordsOffset = reader.ReadUInt32();
31 | uint layerRecordsOffset = reader.ReadUInt32();
32 | ushort numLayerRecords = reader.ReadUInt16();
33 |
34 | GlyphLayers = new ushort[numLayerRecords];
35 | GlyphPalettes = new ushort[numLayerRecords];
36 |
37 | reader.BaseStream.Seek(offset + baseGlyphRecordsOffset, SeekOrigin.Begin);
38 | for (int i = 0; i < numBaseGlyphRecords; ++i)
39 | {
40 | ushort gid = reader.ReadUInt16();
41 | LayerIndices[gid] = reader.ReadUInt16();
42 | LayerCounts[gid] = reader.ReadUInt16();
43 | }
44 |
45 | reader.BaseStream.Seek(offset + layerRecordsOffset, SeekOrigin.Begin);
46 | for (int i = 0; i < GlyphLayers.Length; ++i)
47 | {
48 | GlyphLayers[i] = reader.ReadUInt16();
49 | GlyphPalettes[i] = reader.ReadUInt16();
50 | }
51 | }
52 |
53 | public ushort[] GlyphLayers { get; private set; }
54 | public ushort[] GlyphPalettes { get; private set; }
55 | public readonly Dictionary LayerIndices = new Dictionary();
56 | public readonly Dictionary LayerCounts = new Dictionary();
57 | }
58 | }
59 |
60 |
--------------------------------------------------------------------------------
/OpenFont/Tables.AdvancedLayout/ScriptList.cs:
--------------------------------------------------------------------------------
1 | //Apache2, 2016-present, WinterDev
2 |
3 | using System.Collections.Generic;
4 | using System.IO;
5 |
6 | namespace Typography.OpenFont.Tables
7 | {
8 | public class ScriptList : Dictionary
9 | {
10 | //https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2
11 | // The ScriptList identifies the scripts in a font,
12 | // each of which is represented by a Script table that contains script and language-system data.
13 | // Language system tables reference features, which are defined in the FeatureList.
14 | // Each feature table references the lookup data defined in the LookupList that describes how, when, and where to implement the feature.
15 | private ScriptList() { }
16 | public new ScriptTable this[uint tagName] => TryGetValue(tagName, out ScriptTable ret) ? ret : null;
17 |
18 |
19 | public static ScriptList CreateFrom(BinaryReader reader, long beginAt)
20 | {
21 |
22 | // ScriptList table
23 | // Type Name Description
24 | // uint16 scriptCount Number of ScriptRecords
25 | // ScriptRecord scriptRecords[scriptCount] Array of ScriptRecords,listed alphabetically by ScriptTag
26 | //
27 | // ScriptRecord
28 | // Type Name Description
29 | // Tag scriptTag 4-byte ScriptTag identifier
30 | // Offset16 scriptOffset Offset to Script table-from beginning of ScriptList
31 |
32 | reader.BaseStream.Seek(beginAt, SeekOrigin.Begin);
33 |
34 | ushort scriptCount = reader.ReadUInt16();
35 | ScriptList scriptList = new ScriptList();
36 |
37 | // Read records (tags and table offsets)
38 | uint[] scriptTags = new uint[scriptCount];
39 | ushort[] scriptOffsets = new ushort[scriptCount];
40 | for (int i = 0; i < scriptCount; ++i)
41 | {
42 | scriptTags[i] = reader.ReadUInt32();
43 | scriptOffsets[i] = reader.ReadUInt16();
44 | }
45 |
46 | // Read each table and add it to the dictionary
47 | for (int i = 0; i < scriptCount; ++i)
48 | {
49 | ScriptTable scriptTable = ScriptTable.CreateFrom(reader, beginAt + scriptOffsets[i]);
50 | scriptTable.scriptTag = scriptTags[i];
51 | scriptList.Add(scriptTags[i], scriptTable);
52 | }
53 |
54 | return scriptList;
55 | }
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/Schwabra/Migrations/InitialCreate.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.EntityFrameworkCore.Migrations;
2 |
3 | namespace Schwabra.Migrations
4 | {
5 | public partial class InitialCreate : Migration
6 | {
7 | protected override void Up(MigrationBuilder migrationBuilder)
8 | {
9 | migrationBuilder.CreateTable(
10 | name: "station",
11 | columns: table => new
12 | {
13 | id = table.Column(type: "INTEGER", nullable: false)
14 | .Annotation("Sqlite:Autoincrement", true),
15 | name = table.Column(type: "TEXT", nullable: true),
16 | filename = table.Column(type: "TEXT", nullable: true),
17 | path = table.Column(type: "TEXT", nullable: true)
18 | },
19 | constraints: table =>
20 | {
21 | table.PrimaryKey("PK_station", x => x.id);
22 | });
23 |
24 | migrationBuilder.CreateTable(
25 | name: "result",
26 | columns: table => new
27 | {
28 | id = table.Column(type: "INTEGER", nullable: false)
29 | .Annotation("Sqlite:Autoincrement", true),
30 | num = table.Column(type: "INTEGER", nullable: false),
31 | title = table.Column(type: "TEXT", nullable: true),
32 | value = table.Column(type: "INTEGER", nullable: false),
33 | value_percent = table.Column(type: "REAL", nullable: true),
34 | Stationid = table.Column(type: "INTEGER", nullable: true)
35 | },
36 | constraints: table =>
37 | {
38 | table.PrimaryKey("PK_result", x => x.id);
39 | table.ForeignKey(
40 | name: "FK_result_station_Stationid",
41 | column: x => x.Stationid,
42 | principalTable: "station",
43 | principalColumn: "id",
44 | onDelete: ReferentialAction.Restrict);
45 | });
46 |
47 | migrationBuilder.CreateIndex(
48 | name: "IX_result_Stationid",
49 | table: "result",
50 | column: "Stationid");
51 | }
52 |
53 | protected override void Down(MigrationBuilder migrationBuilder)
54 | {
55 | migrationBuilder.DropTable(
56 | name: "result");
57 |
58 | migrationBuilder.DropTable(
59 | name: "station");
60 | }
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/Schwabra/Migrations/ElectionContextModelSnapshot.cs:
--------------------------------------------------------------------------------
1 | //
2 | using System;
3 | using Microsoft.EntityFrameworkCore;
4 | using Microsoft.EntityFrameworkCore.Infrastructure;
5 | using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
6 | using Schwabra;
7 |
8 | namespace Schwabra.Migrations
9 | {
10 | [DbContext(typeof(ElectionContext))]
11 | partial class ElectionContextModelSnapshot : ModelSnapshot
12 | {
13 | protected override void BuildModel(ModelBuilder modelBuilder)
14 | {
15 | #pragma warning disable 612, 618
16 | modelBuilder
17 | .HasAnnotation("ProductVersion", "5.0.10");
18 |
19 | modelBuilder.Entity("Schwabra.Result", b =>
20 | {
21 | b.Property("id")
22 | .ValueGeneratedOnAdd()
23 | .HasColumnType("INTEGER");
24 |
25 | b.Property("Stationid")
26 | .HasColumnType("INTEGER");
27 |
28 | b.Property("num")
29 | .HasColumnType("INTEGER");
30 |
31 | b.Property("title")
32 | .HasColumnType("TEXT");
33 |
34 | b.Property("value")
35 | .HasColumnType("INTEGER");
36 |
37 | b.Property("value_percent")
38 | .HasColumnType("REAL");
39 |
40 | b.HasKey("id");
41 |
42 | b.HasIndex("Stationid");
43 |
44 | b.ToTable("result");
45 | });
46 |
47 | modelBuilder.Entity("Schwabra.Station", b =>
48 | {
49 | b.Property("id")
50 | .ValueGeneratedOnAdd()
51 | .HasColumnType("INTEGER");
52 |
53 | b.Property("filename")
54 | .HasColumnType("TEXT");
55 |
56 | b.Property("name")
57 | .HasColumnType("TEXT");
58 |
59 | b.Property("path")
60 | .HasColumnType("TEXT");
61 |
62 | b.HasKey("id");
63 |
64 | b.ToTable("station");
65 | });
66 |
67 | modelBuilder.Entity("Schwabra.Result", b =>
68 | {
69 | b.HasOne("Schwabra.Station", null)
70 | .WithMany("rows")
71 | .HasForeignKey("Stationid");
72 | });
73 |
74 | modelBuilder.Entity("Schwabra.Station", b =>
75 | {
76 | b.Navigation("rows");
77 | });
78 | #pragma warning restore 612, 618
79 | }
80 | }
81 | }
82 |
--------------------------------------------------------------------------------
/Schwabra/Migrations/InitialCreate.Designer.cs:
--------------------------------------------------------------------------------
1 | //
2 | using System;
3 | using Microsoft.EntityFrameworkCore;
4 | using Microsoft.EntityFrameworkCore.Infrastructure;
5 | using Microsoft.EntityFrameworkCore.Migrations;
6 | using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
7 | using Schwabra;
8 |
9 | namespace Schwabra.Migrations
10 | {
11 | [DbContext(typeof(ElectionContext))]
12 | [Migration("20210922220720_InitialCreate")]
13 | partial class InitialCreate
14 | {
15 | protected override void BuildTargetModel(ModelBuilder modelBuilder)
16 | {
17 | #pragma warning disable 612, 618
18 | modelBuilder
19 | .HasAnnotation("ProductVersion", "5.0.10");
20 |
21 | modelBuilder.Entity("Schwabra.Result", b =>
22 | {
23 | b.Property("id")
24 | .ValueGeneratedOnAdd()
25 | .HasColumnType("INTEGER");
26 |
27 | b.Property("Stationid")
28 | .HasColumnType("INTEGER");
29 |
30 | b.Property("num")
31 | .HasColumnType("INTEGER");
32 |
33 | b.Property("title")
34 | .HasColumnType("TEXT");
35 |
36 | b.Property("value")
37 | .HasColumnType("INTEGER");
38 |
39 | b.Property("value_percent")
40 | .HasColumnType("REAL");
41 |
42 | b.HasKey("id");
43 |
44 | b.HasIndex("Stationid");
45 |
46 | b.ToTable("result");
47 | });
48 |
49 | modelBuilder.Entity("Schwabra.Station", b =>
50 | {
51 | b.Property("id")
52 | .ValueGeneratedOnAdd()
53 | .HasColumnType("INTEGER");
54 |
55 | b.Property("filename")
56 | .HasColumnType("TEXT");
57 |
58 | b.Property("name")
59 | .HasColumnType("TEXT");
60 |
61 | b.Property("path")
62 | .HasColumnType("TEXT");
63 |
64 | b.HasKey("id");
65 |
66 | b.ToTable("station");
67 | });
68 |
69 | modelBuilder.Entity("Schwabra.Result", b =>
70 | {
71 | b.HasOne("Schwabra.Station", null)
72 | .WithMany("rows")
73 | .HasForeignKey("Stationid");
74 | });
75 |
76 | modelBuilder.Entity("Schwabra.Station", b =>
77 | {
78 | b.Navigation("rows");
79 | });
80 | #pragma warning restore 612, 618
81 | }
82 | }
83 | }
84 |
--------------------------------------------------------------------------------
/OpenFont/Tables.BitmapAndSvgFonts/EBDT.cs:
--------------------------------------------------------------------------------
1 | //MIT, 2019-present, WinterDev
2 | using System;
3 | using System.IO;
4 |
5 | namespace Typography.OpenFont.Tables
6 | {
7 | //from https://docs.microsoft.com/en-us/typography/opentype/spec/ebdt
8 |
9 | //The EBDT table is used to embed monochrome or grayscale bitmap glyph data.
10 | //It is used together with the EBLC table,
11 | //which provides embedded bitmap locators,
12 | //and the EBSC table, which provides embedded bitmap scaling information.
13 |
14 | //OpenType embedded bitmaps are also called “sbits” (for “scaler bitmaps”).
15 | //A set of bitmaps for a face at a given size is called a strike.
16 |
17 | //The EBLC table identifies the sizes and glyph ranges of the sbits,
18 | //and keeps offsets to glyph bitmap data in indexSubTables.
19 |
20 | //The EBDT table then stores the glyph bitmap data,
21 | //in a number of different possible formats.
22 | //Glyph metrics information may be stored in either the EBLC or EBDT table,
23 | //depending upon the indexSubTable and glyph bitmap data formats.
24 |
25 | //The EBSC table identifies sizes that will be handled by scaling up or scaling down other sbit sizes.
26 |
27 |
28 | //The EBDT table is a super set of Apple’s Apple Advanced Typography (AAT) 'bdat' table.
29 |
30 |
31 | ///
32 | /// Embedded Bitmap Data Table
33 | ///
34 | class EBDT : TableEntry
35 | {
36 | public const string _N = "EBDT";
37 | public override string Name => _N;
38 |
39 | protected override void ReadContentFrom(BinaryReader reader)
40 | {
41 | ushort majorVersion = reader.ReadUInt16();
42 | ushort minorVersion = reader.ReadUInt16();
43 |
44 | //The rest of the EBDT table is a collection of bitmap data.
45 | //The data can be in a number of possible formats,
46 | //indicated by information in the EBLC table.
47 |
48 | //Some of the formats contain metric information plus image data,
49 | //and other formats contain only the image data.
50 | //Long word alignment is not required for these sub tables;
51 | //byte alignment is sufficient.
52 |
53 | //There are also two different formats for glyph metrics:
54 | //big glyph metrics and small glyph metrics.
55 | //Big glyph metrics define metrics information
56 | //for both horizontal and vertical layouts.
57 | //This is important in fonts(such as Kanji) where both types of layout may be used.
58 | //Small glyph metrics define metrics information for one layout direction only.
59 | //Which direction applies, horizontal or vertical, is determined by the flags field in the BitmapSize
60 | //tables within the EBLC table.
61 |
62 | }
63 | }
64 | }
--------------------------------------------------------------------------------
/OpenFont/PreviewFontInfo.cs:
--------------------------------------------------------------------------------
1 | //Apache2, 2017-present, WinterDev
2 | //Apache2, 2014-2016, Samuel Carlsson, WinterDev
3 |
4 |
5 | using Typography.OpenFont.Tables;
6 |
7 | namespace Typography.OpenFont
8 | {
9 | public class PreviewFontInfo
10 | {
11 | public readonly string Name;
12 | public readonly string SubFamilyName;
13 | public readonly Extensions.TranslatedOS2FontStyle OS2TranslatedStyle;
14 | public readonly Extensions.OS2FsSelection OS2FsSelection;
15 |
16 | readonly PreviewFontInfo[] _ttcfMembers;
17 |
18 | public Languages Languages { get; }
19 | public NameEntry NameEntry { get; }
20 | public OS2Table OS2Table { get; }
21 |
22 | internal PreviewFontInfo(
23 | NameEntry nameEntry,
24 | OS2Table os2Table,
25 | Languages langs)
26 | {
27 | NameEntry = nameEntry;
28 | OS2Table = os2Table;
29 | Languages = langs;
30 |
31 | Name = nameEntry.FontName;
32 | SubFamilyName = nameEntry.FontSubFamily;
33 | OS2TranslatedStyle = Extensions.TypefaceExtensions.TranslateOS2FontStyle(os2Table);
34 | OS2FsSelection = Extensions.TypefaceExtensions.TranslateOS2FsSelection(os2Table);
35 | }
36 | internal PreviewFontInfo(string fontName, PreviewFontInfo[] ttcfMembers)
37 | {
38 | Name = fontName;
39 | SubFamilyName = "";
40 | _ttcfMembers = ttcfMembers;
41 | Languages = new Languages();
42 | }
43 |
44 | public string TypographicFamilyName => (NameEntry?.TypographicFamilyName) ?? string.Empty;
45 | public string TypographicSubFamilyName => (NameEntry?.TypographyicSubfamilyName) ?? string.Empty;
46 | public string PostScriptName => (NameEntry?.PostScriptName) ?? string.Empty;
47 | public string UniqueFontIden => (NameEntry?.UniqueFontIden) ?? string.Empty;
48 | public string VersionString => (NameEntry?.VersionString) ?? string.Empty;
49 | public ushort WeightClass => (OS2Table != null) ? OS2Table.usWeightClass : ushort.MinValue;
50 | public ushort WidthClass => (OS2Table != null) ? OS2Table.usWidthClass : ushort.MinValue;
51 |
52 |
53 | public int ActualStreamOffset { get; internal set; }
54 | public bool IsWebFont { get; internal set; }
55 | public bool IsFontCollection => _ttcfMembers != null;
56 | ///
57 | /// get font collection's member count
58 | ///
59 | public int MemberCount => _ttcfMembers.Length;
60 | ///
61 | /// get font collection's member
62 | ///
63 | ///
64 | ///
65 | public PreviewFontInfo GetMember(int index) => _ttcfMembers[index];
66 | #if DEBUG
67 | public override string ToString()
68 | {
69 | return (IsFontCollection) ? Name : Name + ", " + SubFamilyName + ", " + OS2TranslatedStyle;
70 | }
71 | #endif
72 | }
73 |
74 |
75 | }
--------------------------------------------------------------------------------
/OpenFont/Tables.Others/HorizontalDeviceMetrics.cs:
--------------------------------------------------------------------------------
1 | //Apache2, 2016-present, WinterDev
2 |
3 | using System.IO;
4 |
5 | namespace Typography.OpenFont.Tables
6 | {
7 |
8 | class HorizontalDeviceMetrics : TableEntry
9 | {
10 | public const string _N = "hdmx";
11 | public override string Name => _N;
12 | //
13 | //https://www.microsoft.com/typography/otspec/hdmx.htm
14 | //The hdmx table relates to OpenType™ fonts with TrueType outlines.
15 | //The Horizontal Device Metrics table stores integer advance widths scaled to particular pixel sizes.
16 | //This allows the font manager to build integer width tables without calling the scaler for each glyph.
17 | //Typically this table contains only selected screen sizes.
18 | //This table is sorted by pixel size.
19 | //The checksum for this table applies to both subtables listed.
20 |
21 | //Note that for non-square pixel grids,
22 | //the character width (in pixels) will be used to determine which device record to use.
23 | //For example, a 12 point character on a device with a resolution of 72x96 would be 12 pixels high and 16 pixels wide.
24 | //The hdmx device record for 16 pixel characters would be used.
25 |
26 | //If bit 4 of the flag field in the 'head' table is not set,
27 | //then it is assumed that the font scales linearly; in this case an 'hdmx' table is not necessary and should not be built.
28 | //If bit 4 of the flag field is set, then one or more glyphs in the font are assumed to scale nonlinearly.
29 | //In this case, performance can be improved by including the 'hdmx' table with one or more important DeviceRecord's for important sizes.
30 | //Please see the chapter “Recommendations for OpenType Fonts” for more detail.
31 |
32 | //The table begins as follows:
33 | //hdmx Header
34 | //Type Name Description
35 | //USHORT version Table version number (0)
36 | //SHORT numRecords Number of device records.
37 | //LONG sizeDeviceRecord Size of a device record, long aligned.
38 | //DeviceRecord records[numRecords] Array of device records.
39 |
40 | //Each DeviceRecord for format 0 looks like this.
41 | //Device Record
42 | //Type Name Description
43 | //BYTE pixelSize Pixel size for following widths (as ppem).
44 | //BYTE maxWidth Maximum width.
45 | //BYTE widths[numGlyphs] Array of widths (numGlyphs is from the 'maxp' table).
46 |
47 | //Each DeviceRecord is padded with 0's to make it long word aligned.
48 |
49 | //Each Width value is the width of the particular glyph, in pixels,
50 | //at the pixels per em (ppem) size listed at the start of the DeviceRecord.
51 |
52 | //The ppem sizes are measured along the y axis.
53 |
54 | protected override void ReadContentFrom(BinaryReader reader)
55 | {
56 |
57 | }
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/OpenFont/ByteOrderSwappingBinaryReader.cs:
--------------------------------------------------------------------------------
1 | //Apache2, 2014-2016, Samuel Carlsson, WinterDev
2 |
3 | using System;
4 | using System.IO;
5 |
6 | namespace Typography.OpenFont
7 | {
8 | class ByteOrderSwappingBinaryReader : BinaryReader
9 | {
10 | //All OpenType fonts use Motorola-style byte ordering (Big Endian)
11 | //
12 | public ByteOrderSwappingBinaryReader(Stream input)
13 | : base(input)
14 | {
15 | }
16 | protected override void Dispose(bool disposing)
17 | {
18 | GC.SuppressFinalize(this);
19 | base.Dispose(disposing);
20 | }
21 | //
22 | //as original
23 | //
24 | //public override byte ReadByte() { return base.ReadByte(); }
25 | //
26 | //we override the 4 methods here
27 | //
28 | public override short ReadInt16() => BitConverter.ToInt16(RR(2), 8 - 2);
29 | public override ushort ReadUInt16() => BitConverter.ToUInt16(RR(2), 8 - 2);
30 | public override uint ReadUInt32() => BitConverter.ToUInt32(RR(4), 8 - 4);
31 | public override ulong ReadUInt64() => BitConverter.ToUInt64(RR(8), 8 - 8);
32 |
33 |
34 | //used in CFF font
35 | public override double ReadDouble() => BitConverter.ToDouble(RR(8), 8 - 8);
36 | //used in CFF font
37 | public override int ReadInt32() => BitConverter.ToInt32(RR(4), 8 - 4);
38 |
39 | //
40 | readonly byte[] _reusable_buffer = new byte[8]; //fix buffer size to 8 bytes
41 | ///
42 | /// read and reverse
43 | ///
44 | ///
45 | ///
46 | private byte[] RR(int count)
47 | {
48 | base.Read(_reusable_buffer, 0, count);
49 | Array.Reverse(_reusable_buffer);
50 | return _reusable_buffer;
51 | }
52 |
53 | //we don't use these methods in our OpenFont, so => throw the exception
54 | public override int PeekChar() { throw new NotImplementedException(); }
55 | public override int Read() { throw new NotImplementedException(); }
56 | public override int Read(byte[] buffer, int index, int count) => base.Read(buffer, index, count);
57 | public override int Read(char[] buffer, int index, int count) { throw new NotImplementedException(); }
58 | public override bool ReadBoolean() { throw new NotImplementedException(); }
59 | public override char ReadChar() { throw new NotImplementedException(); }
60 | public override char[] ReadChars(int count) { throw new NotImplementedException(); }
61 | public override decimal ReadDecimal() { throw new NotImplementedException(); }
62 |
63 | public override long ReadInt64() { throw new NotImplementedException(); }
64 | public override sbyte ReadSByte() { throw new NotImplementedException(); }
65 | public override float ReadSingle() { throw new NotImplementedException(); }
66 | public override string ReadString() { throw new NotImplementedException(); }
67 | //
68 |
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/OpenFont/Tables.AdvancedLayout/AttachmentListTable.cs:
--------------------------------------------------------------------------------
1 | //Apache2, 2016-present, WinterDev
2 |
3 | using System.IO;
4 |
5 | namespace Typography.OpenFont.Tables
6 | {
7 | //https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2
8 | //Attachment List Table
9 |
10 | //The Attachment List table (AttachList) may be used to cache attachment point coordinates along with glyph bitmaps.
11 |
12 | //The table consists of an offset to a Coverage table (Coverage) listing all glyphs that define attachment points in the GPOS table,
13 | //a count of the glyphs with attachment points (GlyphCount), and an array of offsets to AttachPoint tables (AttachPoint).
14 | //The array lists the AttachPoint tables, one for each glyph in the Coverage table, in the same order as the Coverage Index.
15 | //AttachList table
16 | //Type Name Description
17 | //Offset16 Coverage Offset to Coverage table - from beginning of AttachList table
18 | //unint16 GlyphCount Number of glyphs with attachment points
19 | //Offset16 AttachPoint[GlyphCount] Array of offsets to AttachPoint tables-from beginning of AttachList table-in Coverage Index order
20 |
21 | //An AttachPoint table consists of a count of the attachment points on a single glyph (PointCount) and
22 | //an array of contour indices of those points (PointIndex), listed in increasing numerical order.
23 |
24 | //Example 3 at the end of the chapter demonstrates an AttachList table that defines attachment points for two glyphs.
25 | //AttachPoint table
26 | //Type Name Description
27 | //uint16 PointCount Number of attachment points on this glyph
28 | //uint16 PointIndex[PointCount] Array of contour point indices -in increasing numerical order
29 |
30 | class AttachmentListTable
31 | {
32 | AttachPoint[] _attachPoints;
33 | public CoverageTable CoverageTable { get; private set; }
34 | public static AttachmentListTable CreateFrom(BinaryReader reader, long beginAt)
35 | {
36 | AttachmentListTable attachmentListTable = new AttachmentListTable();
37 | reader.BaseStream.Seek(beginAt, SeekOrigin.Begin);
38 | //
39 | ushort coverageOffset = reader.ReadUInt16();
40 | ushort glyphCount = reader.ReadUInt16();
41 | ushort[] attachPointOffsets = Utils.ReadUInt16Array(reader, glyphCount);
42 | //-----------------------
43 | attachmentListTable.CoverageTable = CoverageTable.CreateFrom(reader, beginAt + coverageOffset);
44 | attachmentListTable._attachPoints = new AttachPoint[glyphCount];
45 | for (int i = 0; i < glyphCount; ++i)
46 | {
47 | reader.BaseStream.Seek(beginAt + attachPointOffsets[i], SeekOrigin.Begin);
48 | ushort pointCount = reader.ReadUInt16();
49 | attachmentListTable._attachPoints[i] = new AttachPoint()
50 | {
51 | pointIndices = Utils.ReadUInt16Array(reader, pointCount)
52 | };
53 | }
54 |
55 | return attachmentListTable;
56 | }
57 | struct AttachPoint
58 | {
59 | public ushort[] pointIndices;
60 | }
61 | }
62 |
63 | }
--------------------------------------------------------------------------------
/OpenFont/Tables.Others/VerticalDeviceMetrics.cs:
--------------------------------------------------------------------------------
1 | //Apache2, 2016-present, WinterDev
2 |
3 | using System.IO;
4 |
5 | namespace Typography.OpenFont.Tables
6 | {
7 | class VerticalDeviceMetrics : TableEntry
8 | {
9 | public const string _N = "VDMX";
10 | public override string Name => _N;
11 | //
12 | //https://docs.microsoft.com/en-us/typography/opentype/spec/vdmx
13 | //VDMX - Vertical Device Metrics
14 | //The VDMX table relates to OpenType™ fonts with TrueType outlines.
15 | //Under Windows, the usWinAscent and usWinDescent values from the 'OS/2' table
16 | //will be used to determine the maximum black height for a font at any given size.
17 | //Windows calls this distance the Font Height.
18 | //Because TrueType instructions can lead to Font Heights that differ from the actual scaled and rounded values,
19 | //basing the Font Height strictly on the yMax and yMin can result in “lost pixels.”
20 | //Windows will clip any pixels that extend above the yMax or below the yMin.
21 | //In order to avoid grid fitting the entire font to determine the correct height, the VDMX table has been defined.
22 |
23 | //The VDMX table consists of a header followed by groupings of VDMX records:
24 | Ratio[] _ratios;
25 | protected override void ReadContentFrom(BinaryReader reader)
26 | {
27 | //uint16 version Version number (0 or 1).
28 | //uint16 numRecs Number of VDMX groups present
29 | //uint16 numRatios Number of aspect ratio groupings
30 | //RatioRange ratRange[numRatios] Ratio ranges (see below for more info)
31 | //Offset16 offset[numRatios] Offset from start of this table to the VDMX group for this ratio range.
32 | //---
33 | //RatioRange Record:
34 | //Type Name Description
35 | //uint8 bCharSet Character set (see below).
36 | //uint8 xRatio Value to use for x-Ratio
37 | //uint8 yStartRatio Starting y-Ratio value.
38 | //uint8 yEndRatio Ending y-Ratio value.
39 | ushort version = reader.ReadUInt16();
40 | ushort numRecs = reader.ReadUInt16();
41 | ushort numRatios = reader.ReadUInt16();
42 | _ratios = new Ratio[numRatios];
43 | for (int i = 0; i < numRatios; ++i)
44 | {
45 | _ratios[i] = new Ratio(
46 | reader.ReadByte(),
47 | reader.ReadByte(),
48 | reader.ReadByte(),
49 | reader.ReadByte());
50 | }
51 | ushort[] offsets = Utils.ReadUInt16Array(reader, numRatios);
52 | //------
53 | //actual vdmx group
54 | //TODO: implement this
55 | }
56 | readonly struct Ratio
57 | {
58 | public readonly byte charset;
59 | public readonly byte xRatio;
60 | public readonly byte yStartRatio;
61 | public readonly byte yEndRatio;
62 | public Ratio(byte charset, byte xRatio, byte yStartRatio, byte yEndRatio)
63 | {
64 | this.charset = charset;
65 | this.xRatio = xRatio;
66 | this.yStartRatio = yStartRatio;
67 | this.yEndRatio = yEndRatio;
68 | }
69 | }
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/OpenFont/Tables.TrueType/GlyphLocations.cs:
--------------------------------------------------------------------------------
1 | //MIT, 2018-present, WinterDev
2 | //Apache2, 2014-2016, Samuel Carlsson, WinterDev
3 | //https://www.microsoft.com/typography/otspec/loca.htm
4 |
5 | using System.IO;
6 | namespace Typography.OpenFont.Tables
7 | {
8 | class GlyphLocations : TableEntry
9 | {
10 | public const string _N = "loca";
11 | public override string Name => _N;
12 |
13 |
14 | // loca - Index to Location
15 |
16 | //The indexToLoc table stores the offsets to the locations of the glyphs in the font,
17 | //relative to the beginning of the glyphData table.
18 | //In order to compute the length of the last glyph element,
19 | //there is an extra entry after the last valid index.
20 |
21 | //By definition,
22 | //index zero points to the “missing character,”
23 | //which is the character that appears if a character is not found in the font.
24 | //The missing character is commonly represented by a blank box or a space.
25 | //If the font does not contain an outline for the missing character,
26 | //then the first and second offsets should have the same value.
27 | //This also applies to any other characters without an outline, such as the space character.
28 | //If a glyph has no outline, then loca[n] = loca [n+1].
29 | //In the particular case of the last glyph(s), loca[n] will be equal the length of the glyph data ('glyf') table.
30 | //The offsets must be in ascending order with loca[n] <= loca[n+1].
31 |
32 | //Most routines will look at the 'maxp' table to determine the number of glyphs in the font, but the value in the 'loca' table must agree.
33 |
34 | //There are two versions of this table, the short and the long. The version is specified in the indexToLocFormat entry in the 'head' table.
35 |
36 | uint[] _offsets;
37 | public GlyphLocations(int glyphCount, bool isLongVersion)
38 | {
39 | _offsets = new uint[glyphCount + 1];
40 | this.IsLongVersion = isLongVersion;
41 | }
42 | public bool IsLongVersion { get; private set; }
43 | public uint[] Offsets => _offsets;
44 | public int GlyphCount => _offsets.Length - 1;
45 |
46 | protected override void ReadContentFrom(BinaryReader reader)
47 | {
48 | //Short version
49 | //Type Name Description
50 | //USHORT offsets[n] The actual local offset divided by 2 is stored.
51 | //The value of n is numGlyphs + 1.
52 | //The value for numGlyphs is found in the 'maxp' table.
53 | //-------------------------
54 | //Long version
55 | //Type Name Description
56 | //ULONG offsets[n] The actual local offset is stored.
57 | //The value of n is numGlyphs + 1. The value for numGlyphs is found in the 'maxp' table.
58 |
59 | //Note that the local offsets should be long-aligned, i.e., multiples of 4. Offsets which are not long-aligned may seriously degrade performance of some processors.
60 |
61 | int glyphCount = GlyphCount;
62 | int lim = glyphCount + 1;
63 | _offsets = new uint[lim];
64 | if (IsLongVersion)
65 | {
66 | //long version
67 | for (int i = 0; i < lim; i++)
68 | {
69 | _offsets[i] = reader.ReadUInt32();
70 | }
71 | }
72 | else
73 | {
74 | //short version
75 | for (int i = 0; i < lim; i++)
76 | {
77 | _offsets[i] = (uint)(reader.ReadUInt16() << 1); // =*2
78 | }
79 | }
80 | }
81 | }
82 | }
83 |
--------------------------------------------------------------------------------
/OpenFont/Tables/HorizontalHeader.cs:
--------------------------------------------------------------------------------
1 | //Apache2, 2017-present, WinterDev
2 | //Apache2, 2014-2016, Samuel Carlsson, WinterDev
3 |
4 | using System;
5 | using System.IO;
6 | namespace Typography.OpenFont.Tables
7 | {
8 | ///
9 | /// hhea
10 | ///
11 | class HorizontalHeader : TableEntry
12 | {
13 | public const string _N = "hhea";
14 | public override string Name => _N;
15 |
16 | //https://docs.microsoft.com/en-us/typography/opentype/spec/hhea
17 | //hhea — Horizontal Header Table
18 | //-----
19 | // Type Name Description
20 | //uint16 majorVersion Major version number of the horizontal header table — set to 1.
21 | //uint16 minorVersion Minor version number of the horizontal header table — set to 0.
22 | //FWORD Ascender Typographic ascent(Distance from baseline of highest ascender).
23 | //FWORD Descender Typographic descent(Distance from baseline of lowest descender).
24 | //FWORD LineGap Typographic line gap.
25 | // Negative LineGap values are treated as zero in Windows 3.1, and in Mac OS System 6 and System 7.
26 | //UFWORD advanceWidthMax Maximum advance width value in 'hmtx' table.
27 | //FWORD minLeftSideBearing Minimum left sidebearing value in 'hmtx' table.
28 | //FWORD minRightSideBearing Minimum right sidebearing value; calculated as Min(aw - lsb - (xMax - xMin)).
29 | //FWORD xMaxExtent Max(lsb + (xMax - xMin)).
30 | //int16 caretSlopeRise Used to calculate the slope of the cursor(rise/run); 1 for vertical.
31 | //int16 caretSlopeRun 0 for vertical.
32 | //int16 caretOffset The amount by which a slanted highlight on a glyph needs to be shifted to produce the best appearance.Set to 0 for non-slanted fonts
33 | //int16 (reserved) set to 0
34 | //int16 (reserved) set to 0
35 | //int16 (reserved) set to 0
36 | //int16 (reserved) set to 0
37 | //int16 metricDataFormat 0 for current format.
38 | //uint16 numberOfHMetrics Number of hMetric entries in 'hmtx' table
39 |
40 | public HorizontalHeader()
41 | {
42 | }
43 | protected override void ReadContentFrom(BinaryReader input)
44 | {
45 | Version = input.ReadUInt32(); //major + minor
46 | Ascent = input.ReadInt16();
47 | Descent = input.ReadInt16();
48 | LineGap = input.ReadInt16();
49 |
50 | AdvancedWidthMax = input.ReadUInt16();
51 | MinLeftSideBearing = input.ReadInt16();
52 | MinRightSideBearing = input.ReadInt16();
53 | MaxXExtent = input.ReadInt16();
54 |
55 | CaretSlopRise = input.ReadInt16();
56 | CaretSlopRun = input.ReadInt16();
57 | CaretOffset = input.ReadInt16();
58 |
59 | //reserve 4 int16 fields, int16 x 4 fields
60 | input.BaseStream.Seek(2 * 4, SeekOrigin.Current);
61 |
62 | MetricDataFormat = input.ReadInt16(); // 0
63 | NumberOfHMetrics = input.ReadUInt16();
64 | }
65 | public uint Version { get; private set; }
66 | public short Ascent { get; private set; }
67 | public short Descent { get; private set; }
68 | public short LineGap { get; private set; }
69 | public ushort AdvancedWidthMax { get; private set; }
70 | public short MinLeftSideBearing { get; private set; }
71 | public short MinRightSideBearing { get; private set; }
72 | public short MaxXExtent { get; private set; }
73 | public short CaretSlopRise { get; private set; }
74 | public short CaretSlopRun { get; private set; }
75 | public short CaretOffset { get; private set; }
76 | public short MetricDataFormat { get; private set; }
77 | public ushort NumberOfHMetrics { get; private set; }
78 | }
79 | }
80 |
--------------------------------------------------------------------------------
/Schwabra/Program.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Concurrent;
3 | using System.Collections.Generic;
4 | using System.Globalization;
5 | using System.IO;
6 | using System.Linq;
7 | using System.Threading.Tasks;
8 | using HtmlAgilityPack;
9 |
10 | namespace Schwabra
11 | {
12 | public class Program
13 | {
14 | static int Main(string[] args)
15 | {
16 | if (args.Length != 1)
17 | {
18 | Console.WriteLine("use:");
19 | Console.WriteLine(" dotnet run ");
20 | Console.WriteLine(" dotnet run ");
21 |
22 | return -1;
23 | }
24 |
25 | var inputArg = args[0];
26 | using var dbContext = new ElectionContext();
27 | var processedStations = new ConcurrentBag();
28 | if (Directory.Exists(inputArg))
29 | {
30 | // batch processing
31 | var directory = Directory.GetFiles(inputArg);
32 | Parallel.For(0, directory.Length, i =>
33 | {
34 | var file = directory[i];
35 | try
36 | {
37 | Console.WriteLine($"Processing {file} ({i} from {directory.Length})");
38 | processedStations.Add(Extract(file));
39 | }
40 | catch (Exception)
41 | {
42 | Console.Error.WriteLine($"Error processing file: {file}");
43 | throw;
44 | }
45 | });
46 | dbContext.station.AddRange(processedStations);
47 | }
48 | else
49 | {
50 | dbContext.Add(Extract(inputArg));
51 | }
52 |
53 | Console.WriteLine("Saving changes to sqlite...");
54 | dbContext.SaveChanges();
55 |
56 |
57 | return 0;
58 | }
59 |
60 | private static Station Extract(string inputPath)
61 | {
62 | var inputText = File.ReadAllText(inputPath);
63 | var doc = new HtmlDocument();
64 | doc.LoadHtml(inputText);
65 |
66 | string name = ExtractName(doc);
67 | string path = ExtractPath(doc);
68 | var rows = ExtractRows(doc).ToArray();
69 | var station = new Station()
70 | {
71 | filename = inputPath,
72 | name = name,
73 | path = path
74 | };
75 | station.rows.AddRange(rows);
76 |
77 | return station;
78 | }
79 |
80 | public static string ExtractName(HtmlDocument doc)
81 | {
82 | foreach (var td in doc.DocumentNode.SelectNodes("//td") ?? Enumerable.Empty())
83 | {
84 | if (td.InnerText.Contains("Наименование избирательной комиссии"))
85 | {
86 | return td.ParentNode.Elements("td").Last().InnerText;
87 | }
88 | }
89 |
90 | return null;
91 | }
92 |
93 | public static string ExtractPath(HtmlDocument doc)
94 | {
95 | var result = new List();
96 | foreach (var node in doc.DocumentNode.SelectSingleNode("//ul[@class='breadcrumb']")?.SelectNodes("li") ?? Enumerable.Empty())
97 | {
98 | var val = node.InnerText.Trim();
99 | if (val != "menu")
100 | result.Add(val);
101 | }
102 |
103 | return string.Join(";", result);
104 | }
105 |
106 | public static IEnumerable ExtractRows(HtmlDocument doc)
107 | {
108 | var mainTable = doc.DocumentNode.SelectSingleNode("//table[contains(@class, 'table-sm')]");
109 | foreach (var tr in mainTable?.SelectNodes("tr") ?? Enumerable.Empty())
110 | {
111 | if (tr.InnerText.Trim() == "") continue;
112 | var tds = tr.Elements("td").ToArray();
113 | var numNode = tds[0];
114 | var titleNode = tds[1];
115 | var valNode = tds[2];
116 |
117 | var num = int.Parse(numNode.InnerText);
118 | var title = titleNode.InnerText;
119 | double? percent = null;
120 | if (!int.TryParse(valNode.InnerText, out var value))
121 | {
122 | var nums = valNode.InnerText.Split(new []{' ', '\r', '\n'}, StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries).ToArray();
123 | value = int.Parse(nums[0]);
124 | percent = double.Parse(nums[1].TrimEnd('%'), CultureInfo.InvariantCulture);
125 | }
126 |
127 | yield return new Result(){ num = num, title = title, value = value, value_percent = percent};
128 | }
129 | }
130 | }
131 | }
--------------------------------------------------------------------------------
/OpenFont/Tables/MaxProfile.cs:
--------------------------------------------------------------------------------
1 | //Apache2, 2017-present, WinterDev
2 | //Apache2, 2014-2016, Samuel Carlsson, WinterDev
3 |
4 |
5 | using System.IO;
6 | namespace Typography.OpenFont.Tables
7 | {
8 | //https://docs.microsoft.com/en-us/typography/opentype/spec/maxp
9 | class MaxProfile : TableEntry
10 | {
11 | public const string _N = "maxp";
12 | public override string Name => _N;
13 |
14 | //This table establishes the memory requirements for this font.
15 | //Fonts with CFF data must use Version 0.5 of this table,
16 | //specifying only the numGlyphs field.
17 |
18 | //Fonts with TrueType outlines must use Version 1.0 of this table, where all data is required.
19 |
20 | //Version 0.5
21 | //Type Name Description
22 | //Fixed version 0x00005000 for version 0.5
23 | // (Note the difference in the representation of a non-zero fractional part, in Fixed numbers.)
24 | //uint16 numGlyphs The number of glyphs in the font.
25 |
26 | //Version 1.0
27 | //Type Name Description
28 | //Fixed version 0x00010000 for version 1.0.
29 | //uint16 numGlyphs The number of glyphs in the font.
30 | //uint16 maxPoints Maximum points in a non-composite glyph.
31 | //uint16 maxContours Maximum contours in a non-composite glyph.
32 | //uint16 maxCompositePoints Maximum points in a composite glyph.
33 | //uint16 maxCompositeContours Maximum contours in a composite glyph.
34 | //uint16 maxZones 1 if instructions do not use the twilight zone (Z0), or 2 if instructions do use Z0; should be set to 2 in most cases.
35 | //uint16 maxTwilightPoints Maximum points used in Z0.
36 | //uint16 maxStorage Number of Storage Area locations.
37 | //uint16 maxFunctionDefs Number of FDEFs, equal to the highest function number + 1.
38 | //uint16 maxInstructionDefs Number of IDEFs.
39 | //uint16 maxStackElements Maximum stack depth across Font Program ('fpgm' table), CVT Program('prep' table) and all glyph instructions(in the 'glyf' table).
40 | //uint16 maxSizeOfInstructions Maximum byte count for glyph instructions.
41 | //uint16 maxComponentElements Maximum number of components referenced at “top level” for any composite glyph.
42 | //uint16 maxComponentDepth Maximum levels of recursion; 1 for simple components.
43 |
44 | public uint Version { get; private set; }
45 | public ushort GlyphCount { get; private set; }
46 | public ushort MaxPointsPerGlyph { get; private set; }
47 | public ushort MaxContoursPerGlyph { get; private set; }
48 | public ushort MaxPointsPerCompositeGlyph { get; private set; }
49 | public ushort MaxContoursPerCompositeGlyph { get; private set; }
50 | public ushort MaxZones { get; private set; }
51 | public ushort MaxTwilightPoints { get; private set; }
52 | public ushort MaxStorage { get; private set; }
53 | public ushort MaxFunctionDefs { get; private set; }
54 | public ushort MaxInstructionDefs { get; private set; }
55 | public ushort MaxStackElements { get; private set; }
56 | public ushort MaxSizeOfInstructions { get; private set; }
57 | public ushort MaxComponentElements { get; private set; }
58 | public ushort MaxComponentDepth { get; private set; }
59 |
60 | protected override void ReadContentFrom(BinaryReader input)
61 | {
62 | Version = input.ReadUInt32(); // 0x00010000 == 1.0
63 | GlyphCount = input.ReadUInt16();
64 | MaxPointsPerGlyph = input.ReadUInt16();
65 | MaxContoursPerGlyph = input.ReadUInt16();
66 | MaxPointsPerCompositeGlyph = input.ReadUInt16();
67 | MaxContoursPerCompositeGlyph = input.ReadUInt16();
68 | MaxZones = input.ReadUInt16();
69 | MaxTwilightPoints = input.ReadUInt16();
70 | MaxStorage = input.ReadUInt16();
71 | MaxFunctionDefs = input.ReadUInt16();
72 | MaxInstructionDefs = input.ReadUInt16();
73 | MaxStackElements = input.ReadUInt16();
74 | MaxSizeOfInstructions = input.ReadUInt16();
75 | MaxComponentElements = input.ReadUInt16();
76 | MaxComponentDepth = input.ReadUInt16();
77 | }
78 | }
79 | }
80 |
--------------------------------------------------------------------------------
/OpenFont/Tables/HorizontalMetrics.cs:
--------------------------------------------------------------------------------
1 | //Apache2, 2017-present, WinterDev
2 | //Apache2, 2014-2016, Samuel Carlsson, WinterDev
3 |
4 | using System;
5 | using System.Collections.Generic;
6 | using System.IO;
7 | namespace Typography.OpenFont.Tables
8 | {
9 | ///
10 | /// hmtx
11 | ///
12 | class HorizontalMetrics : TableEntry
13 | {
14 | public const string _N = "hmtx";
15 | public override string Name => _N;
16 | //
17 | //https://docs.microsoft.com/en-us/typography/opentype/spec/hmtx
18 | // A font rendering engine must use the advanceWidths in the hmtx table for the advances of a CFF OFF font,
19 | //even though the CFF table specifies its own glyph widths.//***
20 |
21 | //Note that fonts in a Font Collection which share a CFF table may specify different advanceWidths in their hmtx table for a particular glyph index.
22 | //For any glyph, xmax and xmin are given in 'glyf' table, lsb and aw are given in 'hmtx' table. rsb is calculated as follows:
23 | // rsb = aw - (lsb + xmax - xmin)
24 | //If pp1 and pp2 are phantom points used to control lsb and rsb, their initial position in x is calculated as follows:
25 | // pp1 = xmin - lsb
26 | // pp2 = pp1 + aw
27 |
28 |
29 | //NOTE:
30 | //lsb=> left-side bearing
31 | //rsb=> right-side bearing
32 | //aw=> advance width
33 |
34 | readonly ushort[] _advanceWidths; //in font design unit
35 | readonly short[] _leftSideBearings;//lsb, in font design unit
36 | readonly int _numOfHMetrics;
37 | readonly int _numGlyphs;
38 | public HorizontalMetrics(ushort numOfHMetrics, ushort numGlyphs)
39 | {
40 | //The value numOfHMetrics comes from the 'hhea' table**
41 | _advanceWidths = new ushort[numGlyphs];
42 | _leftSideBearings = new short[numGlyphs];
43 | _numOfHMetrics = numOfHMetrics;
44 | _numGlyphs = numGlyphs;
45 | #if DEBUG
46 | if (numGlyphs < numOfHMetrics)
47 | {
48 | throw new NotSupportedException();
49 | }
50 | #endif
51 | }
52 |
53 | public ushort GetAdvanceWidth(ushort glyphIndex) => _advanceWidths[glyphIndex];
54 |
55 | public short GetLeftSideBearing(ushort glyphIndex) => _leftSideBearings[glyphIndex];
56 |
57 | public void GetHMetric(ushort glyphIndex, out ushort advWidth, out short lsb)
58 | {
59 | advWidth = _advanceWidths[glyphIndex];
60 | lsb = _leftSideBearings[glyphIndex];
61 | //TODO: calculate other value?
62 | }
63 | protected override void ReadContentFrom(BinaryReader input)
64 | {
65 | //===============================================================================
66 | //1. hMetrics : have both advance width and leftSideBearing(lsb)
67 | //Paired advance width and left side bearing values for each glyph.
68 | //The value numOfHMetrics comes from the 'hhea' table**
69 | //If the font is monospaced, only one entry need be in the array,
70 | //but that entry is required. The last entry applies to all subsequent glyphs
71 |
72 | int gid = 0; //gid=> glyphIndex
73 |
74 | int numOfHMetrics = _numOfHMetrics;
75 | for (int i = 0; i < numOfHMetrics; i++)
76 | {
77 | _advanceWidths[gid] = input.ReadUInt16();
78 | _leftSideBearings[gid] = input.ReadInt16();
79 |
80 | gid++;//***
81 | }
82 |
83 | //===============================================================================
84 | //2. (only) LeftSideBearing: (same advanced width (eg. monospace font), vary only left side bearing)
85 | //Here the advanceWidth is assumed to be the same as the advanceWidth for the last entry above.
86 | //The number of entries in this array is derived from numGlyphs (from 'maxp' table) minus numberOfHMetrics.
87 |
88 | int nEntries = _numGlyphs - numOfHMetrics;
89 | ushort advanceWidth = _advanceWidths[numOfHMetrics - 1];
90 |
91 | for (int i = 0; i < nEntries; i++)
92 | {
93 | _advanceWidths[gid] = advanceWidth;
94 | _leftSideBearings[gid] = input.ReadInt16();
95 |
96 | gid++;//***
97 | }
98 | }
99 | }
100 | }
101 |
--------------------------------------------------------------------------------
/OpenFont/Tables.BitmapAndSvgFonts/CBDT.cs:
--------------------------------------------------------------------------------
1 | //MIT, 2019-present, WinterDev
2 | using System;
3 | using System.IO;
4 | using Typography.OpenFont.Tables.BitmapFonts;
5 |
6 | namespace Typography.OpenFont.Tables
7 | {
8 | //test font=> NotoColorEmoji.ttf
9 |
10 | //from https://docs.microsoft.com/en-us/typography/opentype/spec/cbdt
11 |
12 | //Table structure
13 |
14 | //The CBDT table is used to embed color bitmap glyph data. It is used together with the CBLC table,
15 | //which provides embedded bitmap locators.
16 | //The formats of these two tables are backward compatible with the EBDT and EBLC tables
17 | //used for embedded monochrome and grayscale bitmaps.
18 |
19 | //The CBDT table begins with a header containing simply the table version number.
20 | //Type Name Description
21 | //uint16 majorVersion Major version of the CBDT table, = 3.
22 | //uint16 minorVersion Minor version of the CBDT table, = 0.
23 |
24 | //Note that the first version of the CBDT table is 3.0.
25 |
26 | //The rest of the CBDT table is a collection of bitmap data.
27 | //The data can be presented in three possible formats,
28 | //indicated by information in the CBLC table.
29 | //Some of the formats contain metric information plus image data,
30 | //and other formats contain only the image data. Long word alignment is not required for these subtables;
31 | //byte alignment is sufficient.
32 |
33 | class CBDT : TableEntry, IDisposable
34 | {
35 | public const string _N = "CBDT";
36 | public override string Name => _N;
37 |
38 | readonly GlyphBitmapDataFmt17 _format17 = new GlyphBitmapDataFmt17();
39 | readonly GlyphBitmapDataFmt18 _format18 = new GlyphBitmapDataFmt18();
40 | readonly GlyphBitmapDataFmt19 _format19 = new GlyphBitmapDataFmt19();
41 |
42 |
43 | System.IO.MemoryStream _ms; //sub-stream contains image data
44 | Typography.OpenFont.ByteOrderSwappingBinaryReader _binReader;
45 |
46 | public void Dispose()
47 | {
48 | RemoveOldMemoryStreamAndReaders();
49 | }
50 |
51 | public void RemoveOldMemoryStreamAndReaders()
52 | {
53 | try
54 | {
55 | if (_binReader != null)
56 | {
57 | ((System.IDisposable)_binReader).Dispose();
58 | _binReader = null;
59 | }
60 | if (_ms != null)
61 | {
62 | _ms.Dispose();
63 | _ms = null;
64 | }
65 | }
66 | catch (Exception ex)
67 | {
68 | //
69 | }
70 | }
71 | protected override void ReadContentFrom(BinaryReader reader)
72 | {
73 |
74 | //we copy data from the input mem stream
75 | //and store inside this table for later use.
76 | RemoveOldMemoryStreamAndReaders();
77 |
78 | //-------------------
79 | byte[] data = reader.ReadBytes((int)this.Header.Length);//***
80 | _ms = new MemoryStream(data);
81 | _binReader = new ByteOrderSwappingBinaryReader(_ms);
82 | }
83 | public void FillGlyphInfo(Glyph glyph)
84 | {
85 | //int srcOffset, int srcLen, int srcFormat,
86 | _binReader.BaseStream.Position = glyph.BitmapStreamOffset;
87 | switch (glyph.BitmapFormat)
88 | {
89 | case 17: _format17.FillGlyphInfo(_binReader, glyph); break;
90 | case 18: _format18.FillGlyphInfo(_binReader, glyph); break;
91 | case 19: _format19.FillGlyphInfo(_binReader, glyph); break;
92 | default:
93 | throw new NotSupportedException();
94 | }
95 | }
96 | public void CopyBitmapContent(Glyph glyph, System.IO.Stream outputStream)
97 | {
98 | //1
99 | _binReader.BaseStream.Position = glyph.BitmapStreamOffset;
100 | switch (glyph.BitmapFormat)
101 | {
102 | case 17: _format17.ReadRawBitmap(_binReader, glyph, outputStream); break;
103 | case 18: _format18.ReadRawBitmap(_binReader, glyph, outputStream); break;
104 | case 19: _format19.ReadRawBitmap(_binReader, glyph, outputStream); break;
105 | default:
106 | throw new NotSupportedException();
107 | }
108 | }
109 | }
110 | }
--------------------------------------------------------------------------------
/OpenFont/Tables/Utils.cs:
--------------------------------------------------------------------------------
1 | //Apache2, 2017-present, WinterDev
2 | //Apache2, 2014-2016, Samuel Carlsson, WinterDev
3 |
4 | using System;
5 | using System.Text;
6 | using System.IO;
7 |
8 | namespace Typography.OpenFont
9 | {
10 | static class Utils
11 | {
12 | ///
13 | /// read float, 2.14 format
14 | ///
15 | ///
16 | ///
17 | public static float ReadF2Dot14(this BinaryReader reader)
18 | {
19 | return ((float)reader.ReadInt16()) / (1 << 14); /* Format 2.14 */
20 | }
21 |
22 | public static Bounds ReadBounds(BinaryReader input)
23 | {
24 | return new Bounds(
25 | input.ReadInt16(),//xmin
26 | input.ReadInt16(), //ymin
27 | input.ReadInt16(), //xmax
28 | input.ReadInt16());//ymax
29 | }
30 |
31 | public static string TagToString(uint tag)
32 | {
33 | byte[] bytes = BitConverter.GetBytes(tag);
34 | Array.Reverse(bytes);
35 | return Encoding.UTF8.GetString(bytes, 0, bytes.Length);
36 | }
37 |
38 | public static int ReadUInt24(this BinaryReader reader)
39 | {
40 | byte highByte = reader.ReadByte();
41 | return (highByte << 16) | reader.ReadUInt16();
42 | }
43 | ///
44 | /// 16.16 float format
45 | ///
46 | ///
47 | ///
48 | public static float ReadFixed(this BinaryReader reader)
49 | {
50 | //16.16 format
51 | return (float)reader.ReadUInt32() / (1 << 16);
52 | }
53 |
54 | public static ushort[] ReadUInt16Array(this BinaryReader reader, int nRecords)
55 | {
56 | ushort[] arr = new ushort[nRecords];
57 | for (int i = 0; i < arr.Length; ++i)
58 | {
59 | arr[i] = reader.ReadUInt16();
60 | }
61 | return arr;
62 | }
63 | public static uint[] ReadUInt16ArrayAsUInt32Array(this BinaryReader reader, int nRecords)
64 | {
65 | uint[] arr = new uint[nRecords];
66 | for (int i = 0; i < arr.Length; ++i)
67 | {
68 | arr[i] = reader.ReadUInt16();
69 | }
70 | return arr;
71 | }
72 | public static uint[] ReadUInt32Array(this BinaryReader reader, int nRecords)
73 | {
74 | uint[] arr = new uint[nRecords];
75 | for (int i = 0; i < arr.Length; ++i)
76 | {
77 | arr[i] = reader.ReadUInt32();
78 | }
79 | return arr;
80 | }
81 |
82 | public static T[] CloneArray(T[] original, int newArrLenExtend = 0)
83 | {
84 | int orgLen = original.Length;
85 | T[] newClone = new T[orgLen + newArrLenExtend];
86 | Array.Copy(original, newClone, orgLen);
87 | return newClone;
88 | }
89 |
90 | public static T[] ConcatArray(T[] arr1, T[] arr2)
91 | {
92 | T[] newArr = new T[arr1.Length + arr2.Length];
93 | Array.Copy(arr1, 0, newArr, 0, arr1.Length);
94 | Array.Copy(arr2, 0, newArr, arr1.Length, arr2.Length);
95 | return newArr;
96 | }
97 |
98 | public static void WarnUnimplemented(string format, params object[] args)
99 | {
100 | #if DEBUG
101 | System.Diagnostics.Debug.WriteLine("!STUB! " + string.Format(format, args));
102 | #endif
103 | }
104 |
105 | internal static void WarnUnimplementedCollectAssocGlyphs(string msg)
106 | {
107 | #if DEBUG
108 | System.Diagnostics.Debug.WriteLine("!STUB! UnimplementedCollectAssocGlyph :" + msg);
109 | #endif
110 | }
111 | #if DEBUG
112 | public static bool dbugIsDiff(GlyphPointF[] set1, GlyphPointF[] set2)
113 | {
114 | int j = set1.Length;
115 | if (j != set2.Length)
116 | {
117 | //yes, diff
118 | return true;
119 | }
120 | for (int i = j - 1; i >= 0; --i)
121 | {
122 | if (!set1[i].dbugIsEqualsWith(set2[i]))
123 | {
124 | //yes, diff
125 | return true;
126 | }
127 | }
128 | //no, both are the same
129 | return false;
130 | }
131 | #endif
132 | }
133 | }
134 |
--------------------------------------------------------------------------------
/OpenFont/Tables.CFF/CFFTable.cs:
--------------------------------------------------------------------------------
1 | //Apache2, 2018, Apache/PDFBox Authors ( https://github.com/apache/pdfbox)
2 | //
3 | //
4 | //Apache PDFBox
5 | //Copyright 2014 The Apache Software Foundation
6 |
7 | //This product includes software developed at
8 | //The Apache Software Foundation(http://www.apache.org/).
9 |
10 | //Based on source code originally developed in the PDFBox and
11 | //FontBox projects.
12 |
13 | //Copyright (c) 2002-2007, www.pdfbox.org
14 |
15 | //Based on source code originally developed in the PaDaF project.
16 | //Copyright (c) 2010 Atos Worldline SAS
17 |
18 | //Includes the Adobe Glyph List
19 | //Copyright 1997, 1998, 2002, 2007, 2010 Adobe Systems Incorporated.
20 |
21 | //Includes the Zapf Dingbats Glyph List
22 | //Copyright 2002, 2010 Adobe Systems Incorporated.
23 |
24 | //Includes OSXAdapter
25 | //Copyright (C) 2003-2007 Apple, Inc., All Rights Reserved
26 |
27 | //----------------
28 | //ccf1 spec from http://wwwimages.adobe.com/www.adobe.com/content/dam/acom/en/devnet/font/pdfs/5176.CFF.pdf
29 |
30 | //------------------------------------------------------------------
31 | //Apache2, 2018-present, WinterDev
32 |
33 |
34 | using System;
35 | using System.Collections.Generic;
36 | using System.IO;
37 | using System.Text;
38 |
39 | using Typography.OpenFont.CFF;
40 |
41 | namespace Typography.OpenFont.Tables
42 | {
43 |
44 | //from https://docs.microsoft.com/en-us/typography/opentype/spec/cff
45 | //This table contains a Compact Font Format font representation (also known as a PostScript Type 1, or CIDFont)
46 | //and is structured according to
47 | //Adobe Technical Note #5176: “The Compact Font Format Specification,” (https://wwwimages2.adobe.com/content/dam/acom/en/devnet/font/pdfs/5176.CFF.pdf)
48 | //and
49 | //Adobe Technical Note #5177: “Type 2 Charstring Format.” (https://wwwimages2.adobe.com/content/dam/acom/en/devnet/font/pdfs/5177.Type2.pdf)
50 |
51 |
52 | //...
53 | // ... glyph data is accessed through the CharStrings INDEX of the CFF table.
54 |
55 | //...
56 | //The CFF Top DICT must specify a CharstringType value of 2.
57 | //The numGlyphs field in the 'maxp' table must be the same as the number of entries in the CFF's CharStrings INDEX.
58 | //The OpenType font glyph index is the same as the CFF glyph index for all glyphs in the font.
59 |
60 | //Note that, in an OpenType font collection file, a single 'CFF ' table can be shared across multiple fonts;
61 | //names used by applications must be those provided in the 'name' table, not the Name INDEX entry.
62 | //The CFF Top DICT must specify a CharstringType value of 2.
63 | //The numGlyphs field in the 'maxp' table must be the same as the number of entries in the CFF’s CharStrings INDEX.
64 | //The OpenType font glyph index is the same as the CFF glyph index for all glyphs in the font.
65 |
66 | class CFFTable : TableEntry
67 | {
68 | public const string _N = "CFF ";//4 chars, left 1 blank whitespace
69 | public override string Name => _N;
70 | //
71 |
72 | Cff1FontSet _cff1FontSet;
73 | //
74 | internal Cff1FontSet Cff1FontSet => _cff1FontSet;
75 | protected override void ReadContentFrom(BinaryReader reader)
76 | {
77 | long startAt = reader.BaseStream.Position;
78 | //
79 | //
80 | //Table 8 Header Format
81 | //Type Name Description
82 | //Card8 major Format major version(starting at 1)
83 | //Card8 minor Format minor version(starting at 0)
84 | //Card8 hdrSize Header size(bytes)
85 | //OffSize offSize Absolute offset(0) size
86 | byte[] header = reader.ReadBytes(4);
87 | byte major = header[0];
88 | byte minor = header[1];
89 | byte hdrSize = header[2];
90 | byte offSize = header[3];
91 | ////---------
92 | //name index
93 |
94 | switch (major)
95 | {
96 | default: throw new NotSupportedException();
97 | case 1:
98 | {
99 | Cff1Parser cff1 = new Cff1Parser();
100 | cff1.ParseAfterHeader(startAt, reader);
101 | _cff1FontSet = cff1.ResultCff1FontSet;
102 | }
103 | break;
104 | case 2:
105 | {
106 | Cff2Parser cff2 = new Cff2Parser();
107 | cff2.ParseAfterHeader(reader);
108 | }
109 | break;
110 | }
111 | }
112 |
113 | }
114 |
115 |
116 | }
--------------------------------------------------------------------------------
/OpenFont/Tables.Others/VerticalMetrics.cs:
--------------------------------------------------------------------------------
1 | //Apache2, 2017-present, WinterDev
2 |
3 | using System;
4 | using System.IO;
5 | namespace Typography.OpenFont.Tables
6 | {
7 | ///
8 | /// vertical metrics table
9 | ///
10 | class VerticalMetrics : TableEntry
11 | {
12 | public const string _N = "vmtx";
13 | public override string Name => _N;
14 |
15 | // https://docs.microsoft.com/en-us/typography/opentype/spec/vmtx
16 | // vmtx - Vertical Metrics Table
17 |
18 | //The vertical metrics table allows you to specify the vertical spacing for each glyph in a vertical font.
19 | //This table consists of either one or two arrays that contain metric information(the advance heights and top sidebearings)
20 | //for the vertical layout of each of the glyphs in the font.
21 | //The vertical metrics coordinate system is shown below.
22 |
23 |
24 | //Vertical Metrics Table Format
25 |
26 | //The overall structure of the vertical metrics table consists of two arrays shown below:
27 | //the vMetrics array followed by an array of top side bearings.
28 | //
29 | //The top side bearing is measured relative to the top of the origin of glyphs,
30 | //for vertical composition of ideographic glyphs.
31 | //
32 | //This table does not have a header,
33 | //but does require that the number of glyphs included in the two arrays equals the total number of glyphs in the font.
34 | //
35 | //The number of entries in the vMetrics array is determined by the value of the numOfLongVerMetrics field of the vertical header table.
36 | //
37 | //The vMetrics array contains two values for each entry.
38 | //These are the advance height and the top sidebearing for each glyph included in the array.
39 | //
40 | //In monospaced fonts, such as Courier or Kanji, all glyphs have the same advance height.
41 | //If the font is monospaced, only one entry need be in the first array, but that one entry is required.
42 | //The format of an entry in the vertical metrics array is given below.
43 |
44 | //
45 | //Type Name Description
46 | //uint16 advanceHeight The advance height of the glyph. Unsigned integer in FUnits
47 | //int16 topSideBearing The top sidebearing of the glyph. Signed integer in FUnits.
48 |
49 | //The second array is optional and generally is used for a run of monospaced glyphs in the font.
50 | //Only one such run is allowed per font, and it must be located at the end of the font.
51 | //This array contains the top sidebearings of glyphs not represented in the first array,
52 | //and all the glyphs in this array must have the same advance height as the last entry in the vMetrics array.
53 | //All entries in this array are therefore monospaced.
54 | //
55 | //The number of entries in this array is calculated by subtracting the value of numOfLongVerMetrics from the number of glyphs in the font.
56 | //The sum of glyphs represented in the first array plus the glyphs represented in the second array therefore equals the number of glyphs in the font.
57 | //The format of the top sidebearing array is given below.
58 | //Type Name Description
59 | // int16 topSideBearing[] The top sidebearing of the glyph. Signed integer in FUnits.
60 |
61 | ushort _numOfLongVerMetrics;
62 | AdvanceHeightAndTopSideBearing[] _advHeightAndTopSideBearings;
63 | public VerticalMetrics(ushort numOfLongVerMetrics)
64 | {
65 | _numOfLongVerMetrics = numOfLongVerMetrics;
66 | }
67 | protected override void ReadContentFrom(BinaryReader reader)
68 | {
69 | _advHeightAndTopSideBearings = new AdvanceHeightAndTopSideBearing[_numOfLongVerMetrics];
70 | int m = 0;
71 | for (int i = _numOfLongVerMetrics - 1; i >= 0; --i)
72 | {
73 | _advHeightAndTopSideBearings[m] = new AdvanceHeightAndTopSideBearing(
74 | reader.ReadUInt16(),
75 | reader.ReadInt16()
76 | );
77 | }
78 | }
79 |
80 | public readonly struct AdvanceHeightAndTopSideBearing
81 | {
82 | public readonly ushort advanceHeight;
83 | public readonly short topSideBearing;
84 | public AdvanceHeightAndTopSideBearing(ushort advanceHeight, short topSideBearing)
85 | {
86 | this.advanceHeight = advanceHeight;
87 | this.topSideBearing = topSideBearing;
88 | }
89 | #if DEBUG
90 | public override string ToString()
91 | {
92 | return advanceHeight + "," + topSideBearing;
93 | }
94 | #endif
95 | }
96 |
97 | }
98 | }
--------------------------------------------------------------------------------
/OpenFont/Tables.TrueType/Gasp.cs:
--------------------------------------------------------------------------------
1 | //Apache2, 2016-present, WinterDev
2 | using System;
3 | using System.IO;
4 | namespace Typography.OpenFont.Tables
5 | {
6 | ///
7 | /// Grid-fitting And Scan-conversion Procedure Table
8 | ///
9 | class Gasp : TableEntry
10 | {
11 | public const string _N = "gasp";
12 | public override string Name => _N;
13 | //
14 | //https://docs.microsoft.com/en-us/typography/opentype/spec/gasp
15 |
16 |
17 | // This table contains information which describes the preferred rasterization techniques
18 | //for the typeface when it is rendered on grayscale-capable devices.
19 | //This table also has some use for monochrome devices,
20 | //which may use the table to turn off hinting at very large or small sizes, to improve performance.
21 |
22 | //At very small sizes,
23 | //the best appearance on grayscale devices can usually be achieved by rendering the glyphs
24 | //in grayscale without using hints.
25 | //
26 | //At intermediate sizes, hinting and monochrome rendering will usually produce the best appearance.
27 | //
28 | //At large sizes, the combination of hinting and grayscale rendering will
29 | //typically produce the best appearance.
30 |
31 | //If the 'gasp' table is not present in a typeface,
32 | //the rasterizer may apply default rules to decide how to render the glyphs on grayscale devices.
33 |
34 | //The 'gasp' table consists of a header followed by groupings of 'gasp' records:
35 | GaspRangeRecord[] _rangeRecords;
36 | protected override void ReadContentFrom(BinaryReader reader)
37 | {
38 |
39 | //Type Name Description
40 | //USHORT version Version number (set to 1)
41 | //USHORT numRanges Number of records to follow
42 | //GASPRANGE gaspRange[numRanges] Sorted by ppem
43 |
44 | //Each GASPRANGE record looks like this:
45 | //Type Name Description
46 | //USHORT rangeMaxPPEM Upper limit of range, in PPEM
47 | //USHORT rangeGaspBehavior Flags describing desired rasterizer behavior.
48 | ushort version = reader.ReadUInt16();
49 | ushort numRanges = reader.ReadUInt16();
50 | _rangeRecords = new GaspRangeRecord[numRanges];
51 | for (int i = 0; i < numRanges; ++i)
52 | {
53 | _rangeRecords[i] = new GaspRangeRecord(
54 | reader.ReadUInt16(),
55 | (GaspRangeBehavior)reader.ReadUInt16());
56 | }
57 | }
58 |
59 | [Flags]
60 | enum GaspRangeBehavior : ushort
61 | {
62 | Neither = 0,
63 | GASP_DOGRAY = 0x0002,
64 | GASP_GRIDFIT = 0x0001,
65 | GASP_DOGRAY_GASP_GRIDFIT = 0x0003,
66 | GASP_SYMMETRIC_GRIDFIT = 0x0004,
67 | GASP_SYMMETRIC_SMOOTHING = 0x0008,
68 | GASP_SYMMETRIC_SMOOTHING_GASP_SYMMETRIC_GRIDFIT = 0x000C
69 | }
70 | readonly struct GaspRangeRecord
71 | {
72 | public readonly ushort rangeMaxPPEM;
73 | public readonly GaspRangeBehavior rangeGaspBehavior;
74 | public GaspRangeRecord(ushort rangeMaxPPEM, GaspRangeBehavior rangeGaspBehavior)
75 | {
76 | this.rangeMaxPPEM = rangeMaxPPEM;
77 | this.rangeGaspBehavior = rangeGaspBehavior;
78 | }
79 |
80 | // There are four flags for the rangeGaspBehavior flags:
81 | //Flag Meaning
82 | //GASP_DOGRAY Use grayscale rendering
83 | //GASP_GRIDFIT Use gridfitting
84 | //GASP_SYMMETRIC_SMOOTHING Use smoothing along multiple axes with ClearType®
85 | //Only supported in version 1 gasp
86 | //GASP_SYMMETRIC_GRIDFIT Use gridfitting with ClearType symmetric smoothing
87 | //Only supported in version 1 gasp
88 |
89 | //The set of bit flags may be extended in the future.
90 | //The first two bit flags operate independently of the following two bit flags.
91 | //If font smoothing is enabled, then the first two bit flags are used.
92 | //If ClearType is enabled, then the following two bit flags are used. The seven currently defined values of rangeGaspBehavior would have the following uses:
93 | //Flag Value Meaning
94 |
95 | //GASP_DOGRAY 0x0002 small sizes, typically ppem<9
96 | //GASP_GRIDFIT 0x0001 medium sizes, typically 9<=ppem<=16
97 | //GASP_DOGRAY|GASP_GRIDFIT 0x0003 large sizes, typically ppem>16
98 | //(neither) 0x0000 optional for very large sizes, typically ppem>2048
99 | //GASP_SYMMETRIC_GRIDFIT 0x0004 typically always enabled
100 | //GASP_SYMMETRIC_SMOOTHING 0x0008 larger screen sizes, typically ppem>15, most commonly used with the gridfit flag.
101 | //GASP_SYMMETRIC_SMOOTHING| GASP_SYMMETRIC_GRIDFIT 0x000C larger screen sizes, typically ppem>15
102 | //neither 0x0000 optional for very large sizes, typically ppem>2048
103 | }
104 | }
105 |
106 | }
--------------------------------------------------------------------------------
/OpenFont/Tables.AdvancedLayout/CPAL.cs:
--------------------------------------------------------------------------------
1 | //Apache2, 2017-present Sam Hocevar , WinterDev
2 |
3 | using System.IO;
4 |
5 | namespace Typography.OpenFont.Tables
6 | {
7 | public class CPAL : TableEntry
8 | {
9 | public const string _N = "CPAL";
10 | public override string Name => _N;
11 | //
12 |
13 | byte[] _colorBGRABuffer;
14 |
15 | // Palette Table Header
16 | // Read the CPAL table
17 | // https://docs.microsoft.com/en-us/typography/opentype/spec/cpal
18 | protected override void ReadContentFrom(BinaryReader reader)
19 | {
20 | long beginAt = reader.BaseStream.Position;
21 |
22 | //The CPAL table begins with a header that starts with a version number.
23 | //Currently, only versions 0 and 1 are defined.
24 |
25 | //CPAL version 0
26 |
27 | //The CPAL header version 0 is organized as follows:
28 | //CPAL version 0
29 | //Type Name Description
30 | //uint16 version Table version number (=0).
31 | //uint16 numPaletteEntries Number of palette entries in each palette.
32 | //uint16 numPalettes Number of palettes in the table.
33 | //uint16 numColorRecords Total number of color records, combined for all palettes.
34 | //Offset32 offsetFirstColorRecord Offset from the beginning of CPAL table to the first ColorRecord.
35 | //uint16 colorRecordIndices[numPalettes] Index of each palette’s first color record in the combined color record array.
36 |
37 | //CPAL version 1
38 |
39 | //The CPAL header version 1 adds three additional fields to the end of the table header and is organized as follows:
40 | //CPAL version 1
41 | //Type Name Description
42 | //uint16 version Table version number (=1).
43 | //uint16 numPaletteEntries Number of palette entries in each palette.
44 | //uint16 numPalettes Number of palettes in the table.
45 | //uint16 numColorRecords Total number of color records, combined for all palettes.
46 | //Offset32 offsetFirstColorRecord Offset from the beginning of CPAL table to the first ColorRecord.
47 | //uint16 colorRecordIndices[numPalettes] Index of each palette’s first color record in the combined color record array.
48 | //Offset32 offsetPaletteTypeArray Offset from the beginning of CPAL table to the Palette Type Array. Set to 0 if no array is provided.
49 | //Offset32 offsetPaletteLabelArray Offset from the beginning of CPAL table to the Palette Labels Array. Set to 0 if no array is provided.
50 | //Offset32 offsetPaletteEntryLabelArray Offset from the beginning of CPAL table to the Palette Entry Label Array. Set to 0 if no array is provided.
51 |
52 | ushort version = reader.ReadUInt16();
53 | ushort numPaletteEntries = reader.ReadUInt16(); // XXX: unused?
54 | ushort numPalettes = reader.ReadUInt16();
55 | ColorCount = reader.ReadUInt16(); //numColorRecords
56 | uint offsetFirstColorRecord = reader.ReadUInt32(); //Offset from the beginning of CPAL table to the first ColorRecord.
57 | Palettes = Utils.ReadUInt16Array(reader, numPalettes); //colorRecordIndices, Index of each palette’s first color record in the combined color record array.
58 |
59 | #if DEBUG
60 | if (version == 1)
61 | {
62 | //Offset32 offsetPaletteTypeArray Offset from the beginning of CPAL table to the Palette Type Array. Set to 0 if no array is provided.
63 | //Offset32 offsetPaletteLabelArray Offset from the beginning of CPAL table to the Palette Labels Array. Set to 0 if no array is provided.
64 | //Offset32 offsetPaletteEntryLabelArray Offset from the beginning of CPAL table to the Palette Entry Label Array. Set to 0 if no array is provided.
65 | }
66 | #endif
67 |
68 | //move to color records
69 | reader.BaseStream.Seek(beginAt + offsetFirstColorRecord, SeekOrigin.Begin);
70 | _colorBGRABuffer = reader.ReadBytes(4 * ColorCount);
71 | }
72 |
73 | public ushort[] Palettes { get; private set; }
74 | public ushort ColorCount { get; private set; }
75 | public void GetColor(int colorIndex, out byte r, out byte g, out byte b, out byte a)
76 | {
77 | //Each color record has BGRA values. The color space for these values is sRGB.
78 | //Type Name Description
79 | //uint8 blue Blue value(B0).
80 | //uint8 green Green value(B1).
81 | //uint8 red Red value(B2).
82 | //uint8 alpha Alpha value(B3).
83 |
84 | byte[] colorBGRABuffer = _colorBGRABuffer;
85 | int startAt = colorIndex * 4;//bgra
86 | b = colorBGRABuffer[startAt];
87 | g = colorBGRABuffer[startAt + 1];
88 | r = colorBGRABuffer[startAt + 2];
89 | a = colorBGRABuffer[startAt + 3];
90 | }
91 | }
92 | }
93 |
94 |
--------------------------------------------------------------------------------
/Izbirkom21/FontReplacer.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Concurrent;
3 | using System.Collections.Generic;
4 | using System.IO;
5 | using System.Linq;
6 | using System.Net.Http;
7 | using System.Text.RegularExpressions;
8 | using System.Threading.Tasks;
9 | using ExCSS;
10 | using HtmlAgilityPack;
11 | using Typography.OpenFont;
12 |
13 | namespace Izbirkom21
14 | {
15 | public interface IFontProvider
16 | {
17 | ConcurrentDictionary