[OpenFontFormat] Add Erlang files
This commit is contained in:
parent
9b509e6306
commit
7d5c90bd17
91
OpenFontFormat/erl/font_directory.erl
Normal file
91
OpenFontFormat/erl/font_directory.erl
Normal file
@ -0,0 +1,91 @@
|
|||||||
|
-module(font_directory).
|
||||||
|
-export([parse_font_directory/1]).
|
||||||
|
|
||||||
|
-include("sizes.hrl").
|
||||||
|
|
||||||
|
-define(OFFSET_TABLE_SIZE, (?U32+4*?U16)).
|
||||||
|
parse_offset_table(
|
||||||
|
<<SfntVersion:32,
|
||||||
|
NumTables:16,
|
||||||
|
SearchRange:16,
|
||||||
|
EntrySelector:16,
|
||||||
|
RangeShift:16>>) ->
|
||||||
|
case lists:member(SfntVersion, [16#00010000]) of false -> throw({invalid_sfnt_version, SfntVersion}); true -> ok end,
|
||||||
|
[
|
||||||
|
{sfnt_version, SfntVersion},
|
||||||
|
{num_tables, NumTables},
|
||||||
|
{search_range, SearchRange},
|
||||||
|
{entry_selector, EntrySelector},
|
||||||
|
{range_shift, RangeShift}
|
||||||
|
].
|
||||||
|
|
||||||
|
%% 5.2 (Mandatory)
|
||||||
|
read_table_tag(<<"cmap">>) -> cmap;
|
||||||
|
read_table_tag(<<"head">>) -> head;
|
||||||
|
read_table_tag(<<"hhea">>) -> hhea;
|
||||||
|
read_table_tag(<<"hmtx">>) -> hmtx;
|
||||||
|
read_table_tag(<<"maxp">>) -> maxp;
|
||||||
|
read_table_tag(<<"name">>) -> name;
|
||||||
|
read_table_tag(<<"OS/2">>) -> os2 ;
|
||||||
|
read_table_tag(<<"post">>) -> post;
|
||||||
|
%% 5.3 (TTF)
|
||||||
|
read_table_tag(<<"cvt ">>) -> cvt ;
|
||||||
|
read_table_tag(<<"fpgm">>) -> fpgm;
|
||||||
|
read_table_tag(<<"glyf">>) -> glyf;
|
||||||
|
read_table_tag(<<"loca">>) -> loca;
|
||||||
|
read_table_tag(<<"prep">>) -> prep;
|
||||||
|
read_table_tag(<<"gasp">>) -> gasp;
|
||||||
|
%% TODO: 5.4 (CFF)
|
||||||
|
%% 5.5 (SVG)
|
||||||
|
read_table_tag(<<"SVG ">>) -> svg ;
|
||||||
|
%% 5.6 (Optional)
|
||||||
|
read_table_tag(<<"DSIG">>) -> dsig;
|
||||||
|
read_table_tag(<<"hdmx">>) -> hdmx;
|
||||||
|
read_table_tag(<<"Kern">>) -> kern;
|
||||||
|
read_table_tag(<<"LTSH">>) -> ltsh;
|
||||||
|
read_table_tag(<<"PCLT">>) -> pclt;
|
||||||
|
read_table_tag(<<"VDMX">>) -> vdmx;
|
||||||
|
read_table_tag(<<"vhea">>) -> vhea;
|
||||||
|
read_table_tag(<<"vmtx">>) -> vmtx;
|
||||||
|
read_table_tag(<<"COLR">>) -> colr;
|
||||||
|
read_table_tag(<<"CPAL">>) -> cpal;
|
||||||
|
%% 6.3 (Advanced Features)
|
||||||
|
read_table_tag(<<"BASE">>) -> base;
|
||||||
|
read_table_tag(<<"GDEF">>) -> gdef;
|
||||||
|
read_table_tag(<<"GPOS">>) -> gpos;
|
||||||
|
read_table_tag(<<"GSUB">>) -> gsub;
|
||||||
|
read_table_tag(<<"JSTF">>) -> jstf;
|
||||||
|
read_table_tag(<<"MATH">>) -> math;
|
||||||
|
%% 7.3 (Variable Fonts)
|
||||||
|
read_table_tag(<<"avar">>) -> avar;
|
||||||
|
read_table_tag(<<"cvar">>) -> cvar;
|
||||||
|
read_table_tag(<<"fvar">>) -> fvar;
|
||||||
|
read_table_tag(<<"gvar">>) -> gvar;
|
||||||
|
read_table_tag(<<"HVAR">>) -> hvar;
|
||||||
|
read_table_tag(<<"MVAR">>) -> mvar;
|
||||||
|
read_table_tag(<<"STAT">>) -> stat;
|
||||||
|
read_table_tag(<<"VVAR">>) -> vvar;
|
||||||
|
read_table_tag(<<TableTag:4/bytes>>) -> throw({invalid_table_tag, TableTag}).
|
||||||
|
|
||||||
|
-define(TABLE_DIRECTORY_SIZE(Count), ((?TAG_SIZE+3*?U32)*Count)).
|
||||||
|
parse_table_directory(
|
||||||
|
<<TableTag:?TAG_SIZE/binary,
|
||||||
|
CheckSum:32,
|
||||||
|
Offset:32,
|
||||||
|
Length:32,
|
||||||
|
Tail/binary>>) -> [{read_table_tag(TableTag), [
|
||||||
|
{check_sum, CheckSum},
|
||||||
|
{offset, Offset},
|
||||||
|
{length, Length}
|
||||||
|
]} | parse_table_directory(Tail)];
|
||||||
|
parse_table_directory(<<>>) -> [].
|
||||||
|
|
||||||
|
parse_font_directory(<<OffsetTable_:?OFFSET_TABLE_SIZE/binary, TableDirectoryAndRest/binary>>) ->
|
||||||
|
OffsetTable = parse_offset_table(OffsetTable_),
|
||||||
|
NumTables = proplists:get_value(num_tables, OffsetTable),
|
||||||
|
<<TableDirectory_:?TABLE_DIRECTORY_SIZE(NumTables)/binary, _/binary>> = TableDirectoryAndRest,
|
||||||
|
TableDirectory = parse_table_directory(TableDirectory_),
|
||||||
|
[
|
||||||
|
{offset_table, OffsetTable},
|
||||||
|
{table_directory, TableDirectory}
|
||||||
|
].
|
12
OpenFontFormat/erl/read_utils.erl
Normal file
12
OpenFontFormat/erl/read_utils.erl
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
-module(read_utils).
|
||||||
|
-compile(nowarn_export_all).
|
||||||
|
-compile(export_all).
|
||||||
|
|
||||||
|
read_fixed(<<Int:16, Frac:16>>) -> Int + Frac / 65536.0.
|
||||||
|
|
||||||
|
read_fixed_version(<<Int:16, Frac:16>>) -> Int + Frac / 16#1000 / 10.
|
||||||
|
|
||||||
|
read_long_datetime(<<SecondsSince1904:64>>) ->
|
||||||
|
SecondsTo1904 = calendar:datetime_to_gregorian_seconds({{1904,1,1}, {0,0,0}}),
|
||||||
|
Seconds = SecondsTo1904+SecondsSince1904,
|
||||||
|
calendar:gregorian_seconds_to_datetime(Seconds).
|
15
OpenFontFormat/erl/sizes.hrl
Normal file
15
OpenFontFormat/erl/sizes.hrl
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
-define(U8, 1).
|
||||||
|
-define(U16, 2).
|
||||||
|
-define(U24, 3).
|
||||||
|
-define(U32, 4).
|
||||||
|
-define(U64, 8).
|
||||||
|
|
||||||
|
-define(I8, 1).
|
||||||
|
-define(I16, 2).
|
||||||
|
-define(I24, 3).
|
||||||
|
-define(I32, 4).
|
||||||
|
|
||||||
|
-define(FIXED_SIZE, 4).
|
||||||
|
-define(DATETIME_SIZE, 8).
|
||||||
|
|
||||||
|
-define(TAG_SIZE, 4).
|
15
OpenFontFormat/erl/table.erl
Normal file
15
OpenFontFormat/erl/table.erl
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
-module(table).
|
||||||
|
-export([parse_table/4]).
|
||||||
|
|
||||||
|
-import(head, [parse_head_table/1]).
|
||||||
|
-import(hhea, [parse_hhea_table/1]).
|
||||||
|
-import(maxp, [parse_maxp_table/1]).
|
||||||
|
-import(hmtx, [parse_hmtx_table/1]).
|
||||||
|
|
||||||
|
parse_table(head, Table, _, _) -> parse_head_table(Table);
|
||||||
|
parse_table(hhea, Table, _, _) -> parse_hhea_table(Table);
|
||||||
|
parse_table(maxp, Table, _, _) -> parse_maxp_table(Table);
|
||||||
|
parse_table(hmtx, Table, _, Info) ->
|
||||||
|
[{number_of_h_metrics, NumberOfHMetrics}, {num_glyphs, NumGlyphs}] = Info,
|
||||||
|
parse_hmtx_table(<<NumberOfHMetrics:16, NumGlyphs:16, Table/binary>>);
|
||||||
|
parse_table(TableTag, _, _, _) -> throw({unimplemented_table, TableTag}).
|
46
OpenFontFormat/erl/tables/head.erl
Normal file
46
OpenFontFormat/erl/tables/head.erl
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
-module(head).
|
||||||
|
-export([parse_head_table/1]).
|
||||||
|
|
||||||
|
-include("sizes.hrl").
|
||||||
|
-import(read_utils, [read_fixed/1, read_long_datetime/1]).
|
||||||
|
|
||||||
|
parse_head_table(
|
||||||
|
<<1:16, 0:16,
|
||||||
|
FontRendition:?FIXED_SIZE/binary,
|
||||||
|
CheckSumAdjustment:32,
|
||||||
|
MagicNumber:32,
|
||||||
|
Flags:16/bits,
|
||||||
|
UnitsPerEm:16,
|
||||||
|
Created:?DATETIME_SIZE/binary,
|
||||||
|
Modified:?DATETIME_SIZE/binary,
|
||||||
|
XMin:16/signed,
|
||||||
|
YMin:16/signed,
|
||||||
|
XMax:16/signed,
|
||||||
|
YMax:16/signed,
|
||||||
|
MacStyle:16/bits,
|
||||||
|
LowestRecPPEM:16,
|
||||||
|
FontDirectionHint:16/signed,
|
||||||
|
IndexToLocFormat:16/signed,
|
||||||
|
GlyphDataFormat:16/signed>>) ->
|
||||||
|
case MagicNumber == 16#5F0F3CF5 of false -> throw({invalid_magic_number, MagicNumber}); true -> ok end,
|
||||||
|
case lists:member(IndexToLocFormat, [0, 1]) of false -> throw({invalid_index_to_loc_format, IndexToLocFormat}); true -> ok end,
|
||||||
|
case GlyphDataFormat == 0 of false -> throw({invalid_glyph_data_format, GlyphDataFormat}); true -> ok end,
|
||||||
|
[
|
||||||
|
{major_version, 1},
|
||||||
|
{minor_version, 0},
|
||||||
|
{font_revision, read_fixed(FontRendition)},
|
||||||
|
{check_sum_adjustment, CheckSumAdjustment},
|
||||||
|
{flags, Flags},
|
||||||
|
{units_per_em, UnitsPerEm},
|
||||||
|
{created, read_long_datetime(Created)},
|
||||||
|
{modified, read_long_datetime(Modified)},
|
||||||
|
{x_min, XMin},
|
||||||
|
{y_min, YMin},
|
||||||
|
{x_max, XMax},
|
||||||
|
{y_max, YMax},
|
||||||
|
{mac_style, MacStyle},
|
||||||
|
{lowest_rec_ppem, LowestRecPPEM},
|
||||||
|
{font_direction_hint, FontDirectionHint},
|
||||||
|
{index_to_loc_format, IndexToLocFormat},
|
||||||
|
{glyph_data_format, GlyphDataFormat}
|
||||||
|
].
|
37
OpenFontFormat/erl/tables/hhea.erl
Normal file
37
OpenFontFormat/erl/tables/hhea.erl
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
-module(hhea).
|
||||||
|
-export([parse_hhea_table/1]).
|
||||||
|
|
||||||
|
-include("sizes.hrl").
|
||||||
|
-import(read_utils, [read_fixed/1, read_long_datetime/1]).
|
||||||
|
|
||||||
|
parse_hhea_table(
|
||||||
|
<<1:16, 0:16,
|
||||||
|
Ascender:16/signed,
|
||||||
|
Descender:16/signed,
|
||||||
|
LineGap:16/signed,
|
||||||
|
AdvanceWidthMax:16,
|
||||||
|
MinLeftSideBearing:16/signed,
|
||||||
|
MinRightSideBearing:16/signed,
|
||||||
|
XMaxExtent:16/signed,
|
||||||
|
CaretSlopeRise:16/signed,
|
||||||
|
CaretSlopeRun:16/signed,
|
||||||
|
CaretOffset:16/signed,
|
||||||
|
0:16/signed, 0:16/signed, 0:16/signed, 0:16/signed, %% reserved
|
||||||
|
MetricDataFormat:16/signed, NumberOfHMetrics:16>>) ->
|
||||||
|
case MetricDataFormat == 0 of false -> throw(invalid_metric_data_format); true -> ok end,
|
||||||
|
[
|
||||||
|
{majorVersion, 1},
|
||||||
|
{minorVersion, 0},
|
||||||
|
{ascender, Ascender},
|
||||||
|
{descender, Descender},
|
||||||
|
{line_gap, LineGap},
|
||||||
|
{advance_width_max, AdvanceWidthMax},
|
||||||
|
{min_left_side_bearing, MinLeftSideBearing},
|
||||||
|
{min_right_side_bearing, MinRightSideBearing},
|
||||||
|
{x_max_extent, XMaxExtent},
|
||||||
|
{caret_slope_rise, CaretSlopeRise},
|
||||||
|
{caret_slope_run, CaretSlopeRun},
|
||||||
|
{caret_offset, CaretOffset},
|
||||||
|
{metric_data_format, MetricDataFormat},
|
||||||
|
{number_of_h_metrics, NumberOfHMetrics}
|
||||||
|
].
|
26
OpenFontFormat/erl/tables/hmtx.erl
Normal file
26
OpenFontFormat/erl/tables/hmtx.erl
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
-module(hmtx).
|
||||||
|
-export([parse_hmtx_table/1]).
|
||||||
|
|
||||||
|
-include("sizes.hrl").
|
||||||
|
|
||||||
|
-define(LONG_HOR_METRIC_SIZE, (?U16+?I16)).
|
||||||
|
|
||||||
|
parse_long_hor_metric(<<AdvanceWidth:16, Lsb:16/signed, Rest/binary>>) ->
|
||||||
|
[[
|
||||||
|
{advance_width, AdvanceWidth},
|
||||||
|
{lsb, Lsb}
|
||||||
|
] | parse_long_hor_metric(Rest)];
|
||||||
|
parse_long_hor_metric(<<>>) -> [].
|
||||||
|
|
||||||
|
parse_left_side_bearing(<<LeftSideBearing:16/unsigned, Rest/binary>>) ->
|
||||||
|
[LeftSideBearing | parse_left_side_bearing(Rest)];
|
||||||
|
parse_left_side_bearing(<<>>) -> [].
|
||||||
|
|
||||||
|
parse_hmtx_table(
|
||||||
|
<<NumberOfHMetrics:16, NumGlyphs:16, %% <<NumberOfHMetrics:16, NumGlyphs:16, <<Data>>>>
|
||||||
|
HMetrics:(NumberOfHMetrics*?LONG_HOR_METRIC_SIZE)/binary,
|
||||||
|
LeftSideBearing:((NumGlyphs-NumberOfHMetrics)*?I16)/binary
|
||||||
|
>>) -> [
|
||||||
|
{h_metrics, parse_long_hor_metric(HMetrics)},
|
||||||
|
{left_side_bearing, parse_left_side_bearing(LeftSideBearing)}
|
||||||
|
].
|
52
OpenFontFormat/erl/tables/maxp.erl
Normal file
52
OpenFontFormat/erl/tables/maxp.erl
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
-module(maxp).
|
||||||
|
-export([parse_maxp_table/1]).
|
||||||
|
|
||||||
|
-import(read_utils, [read_fixed_version/1]).
|
||||||
|
|
||||||
|
-include("sizes.hrl").
|
||||||
|
|
||||||
|
parse_maxp_table(
|
||||||
|
<<FixedVersion:?FIXED_SIZE/binary,
|
||||||
|
NumGlyphs:16, Tail/binary>>) ->
|
||||||
|
Version = read_fixed_version(FixedVersion),
|
||||||
|
case lists:member(Version, [0.5, 1.0]) of
|
||||||
|
false -> throw({invalid_version, Version});
|
||||||
|
true -> if Version == 0.5 -> [
|
||||||
|
{version, Version},
|
||||||
|
{num_glyphs, NumGlyphs}
|
||||||
|
]; true ->
|
||||||
|
<<
|
||||||
|
MaxPoints:16,
|
||||||
|
MaxContours:16,
|
||||||
|
MaxCompositePoints:16,
|
||||||
|
MaxCompositeContours:16,
|
||||||
|
MaxZones:16,
|
||||||
|
MaxTwilightPoints:16,
|
||||||
|
MaxStorage:16,
|
||||||
|
MaxFunctionDefs:16,
|
||||||
|
MaxInstructionDefs:16,
|
||||||
|
MaxStackElements:16,
|
||||||
|
MaxSizeOfInstructions:16,
|
||||||
|
MaxComponentElements:16,
|
||||||
|
MaxComponentDepth:16,
|
||||||
|
_/binary
|
||||||
|
>> = Tail,
|
||||||
|
[
|
||||||
|
{version, Version},
|
||||||
|
{num_glyphs, NumGlyphs},
|
||||||
|
{max_points, MaxPoints},
|
||||||
|
{max_contours, MaxContours},
|
||||||
|
{max_composite_points, MaxCompositePoints},
|
||||||
|
{max_composite_contours, MaxCompositeContours},
|
||||||
|
{max_zones, MaxZones},
|
||||||
|
{max_twilight_points, MaxTwilightPoints},
|
||||||
|
{max_storage, MaxStorage},
|
||||||
|
{max_function_defs, MaxFunctionDefs},
|
||||||
|
{max_instruction_defs, MaxInstructionDefs},
|
||||||
|
{max_stack_elements, MaxStackElements},
|
||||||
|
{max_size_of_instructions, MaxSizeOfInstructions},
|
||||||
|
{max_component_elements, MaxComponentElements},
|
||||||
|
{max_component_depth, MaxComponentDepth}
|
||||||
|
]
|
||||||
|
end
|
||||||
|
end.
|
7
OpenFontFormat/erl/tables/name.erl
Normal file
7
OpenFontFormat/erl/tables/name.erl
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
-module(name).
|
||||||
|
-export([parse_name_table/1]).
|
||||||
|
|
||||||
|
parse_name_table(
|
||||||
|
<<0:16, Count:16,
|
||||||
|
Offset:16, _:(Offset-3*16)/binary,
|
||||||
|
Strings/binary>> = Table) -> throw(unimplemented).
|
32
OpenFontFormat/erl/ttf_parser.erl
Normal file
32
OpenFontFormat/erl/ttf_parser.erl
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
-module(ttf_parser).
|
||||||
|
-export([read/1]).
|
||||||
|
|
||||||
|
-import(font_directory, [parse_font_directory/1]).
|
||||||
|
-import(table, [parse_table/4]).
|
||||||
|
|
||||||
|
parse_at_table_directory(File, TableDirectory, TableTag, Info) ->
|
||||||
|
TableDirectoryEntry = proplists:get_value(TableTag, TableDirectory),
|
||||||
|
Offset = proplists:get_value(offset, TableDirectoryEntry),
|
||||||
|
Length = proplists:get_value(length, TableDirectoryEntry),
|
||||||
|
<<_:Offset/binary, Table:Length/binary, _/binary>> = File,
|
||||||
|
parse_table(TableTag, Table, Length, Info).
|
||||||
|
parse_at_table_directory(File, TableDirectory, TableTag) -> parse_at_table_directory(File, TableDirectory, TableTag, {}).
|
||||||
|
|
||||||
|
read(Filename) ->
|
||||||
|
{ok, File} = file:read_file(Filename),
|
||||||
|
FontDirectory = parse_font_directory(File),
|
||||||
|
TableDirectory = proplists:get_value(table_directory, FontDirectory),
|
||||||
|
|
||||||
|
FontHeader = parse_at_table_directory(File, TableDirectory, head),
|
||||||
|
HorizontalHeader = parse_at_table_directory(File, TableDirectory, hhea),
|
||||||
|
MaximumProfile = parse_at_table_directory(File, TableDirectory, maxp),
|
||||||
|
HorizontalMetrics = parse_at_table_directory(File, TableDirectory, hmtx, [
|
||||||
|
{number_of_h_metrics, proplists:get_value(number_of_h_metrics, HorizontalHeader)},
|
||||||
|
{num_glyphs, proplists:get_value(num_glyphs, MaximumProfile)}
|
||||||
|
]),
|
||||||
|
[
|
||||||
|
{font_header, FontHeader},
|
||||||
|
{horizontal_header, HorizontalHeader},
|
||||||
|
{maximum_profile, MaximumProfile},
|
||||||
|
{horizontal_metrics, HorizontalMetrics}
|
||||||
|
].
|
Loading…
Reference in New Issue
Block a user