%% %% %CopyrightBegin% %% %% Copyright Ericsson AB 2008-2009. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in %% compliance with the License. You should have received a copy of the %% Erlang Public License along with this software. If not, it can be %% retrieved online at http://www.erlang.org/. %% %% Software distributed under the License is distributed on an "AS IS" %% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See %% the License for the specific language governing rights and limitations %% under the License. %% %% %CopyrightEnd% %% %% @doc egd_font %% -module(egd_font). -export([load/1, size/1, glyph/2]). -include("egd.hrl"). %% Font represenatation in ets table %% egd_font_table %% %% Information: %% {Key, Description, Size} %% Key :: {Font :: atom(), information} %% Description :: any(), Description header from font file %% Size :: {W :: integer(), H :: integer()} %% %% Glyphs: %% {Key, Translation LSs} where %% Key :: {Font :: atom(), Code :: integer()}, Code = glyph char code %% Translation :: { %% W :: integer(), % BBx width %% H :: integer(), % BBx height %% X0 :: integer(), % X start %% Y0 :: integer(), % Y start %% Xm :: integer(), % Glyph X move when drawing %% } %% LSs :: [[{Xl :: integer(), Xr :: integer()}]] %% The first list is height (top to bottom), the inner list is the list %% of line spans for the glyphs horizontal pixels. %% %%========================================================================== %% %% Interface functions %% %%========================================================================== size(Font) -> [{_Key, _Description, Size}] = ets:lookup(egd_font_table,{Font,information}), Size. glyph(Font, Code) -> [{_Key, Translation, LSs}] = ets:lookup(egd_font_table,{Font,Code}), {Translation, LSs}. load(Filename) -> {ok, Bin} = file:read_file(Filename), Font = erlang:binary_to_term(Bin), load_font_header(Font). %%========================================================================== %% %% Internal functions %% %%========================================================================== %% ETS handler functions initialize_table() -> ets:new(egd_font_table, [named_table, ordered_set, public]). glyph_insert(Font, Code, Translation, LSs) -> Element = {{Font, Code}, Translation, LSs}, ets:insert(egd_font_table, Element). font_insert(Font, Description, Dimensions) -> Element = {{Font, information}, Description, Dimensions}, ets:insert(egd_font_table, Element). %% Font loader functions is_font_loaded(Font) -> try case ets:lookup(egd_font_table, {Font, information}) of [] -> false; _ -> true end catch error:_ -> initialize_table(), false end. load_font_header({_Type, _Version, Font}) -> load_font_body(Font). load_font_body({Key,Desc,W,H,Glyphs,Bitmaps}) -> case is_font_loaded(Key) of true -> Key; false -> % insert dimensions font_insert(Key, Desc, {W,H}), parse_glyphs(Glyphs, Bitmaps, Key), Key end. parse_glyphs([], _ , _Key) -> ok; parse_glyphs([Glyph|Glyphs], Bs, Key) -> {Code, Translation, LSs} = parse_glyph(Glyph, Bs), glyph_insert(Key, Code, Translation, LSs), parse_glyphs(Glyphs, Bs, Key). parse_glyph({Code,W,H,X0,Y0,Xm,Offset}, Bitmasks) -> BytesPerLine = ((W+7) div 8), NumBytes = BytesPerLine*H, <<_:Offset/binary,Bitmask:NumBytes/binary,_/binary>> = Bitmasks, LSs = render_glyph(W,H,X0,Y0,Xm,Bitmask), {Code, {W,H,X0,Y0,Xm}, LSs}. render_glyph(W, H, X0, Y0, Xm, Bitmask) -> render_glyph(W,{0,H},X0,Y0,Xm,Bitmask, []). render_glyph(_W, {H,H}, _X0, _Y0, _Xm, _Bitmask, Out) -> Out; render_glyph(W, {Hi,H}, X0, Y0,Xm, Bitmask , LSs) -> N = ((W+7) div 8), O = N*Hi, <<_:O/binary, Submask/binary>> = Bitmask, LS = render_glyph_horizontal( Submask, % line glyph bitmask {down, W - 1}, % loop state W - 1, % Width []), % Linespans render_glyph(W,{Hi+1,H},X0,Y0,Xm, Bitmask, [LS|LSs]). render_glyph_horizontal(Value, {Pr, Px}, 0, Spans) -> Cr = bit_spin(Value, 0), case {Pr,Cr} of {up , up } -> % closure of interval since its last [{0, Px}|Spans]; {up , down} -> % closure of interval [{1, Px}|Spans]; {down, up } -> % beginning of interval [{0, 0}|Spans]; {down, down} -> % no change in interval Spans end; render_glyph_horizontal(Value, {Pr, Px}, Cx, Spans) -> Cr = bit_spin(Value, Cx), case {Pr,Cr} of {up , up } -> % no change in interval render_glyph_horizontal(Value, {Cr, Px}, Cx - 1, Spans); {up , down} -> % closure of interval render_glyph_horizontal(Value, {Cr, Cx}, Cx - 1, [{Cx+1,Px}|Spans]); {down, up } -> % beginning of interval render_glyph_horizontal(Value, {Cr, Cx}, Cx - 1, Spans); {down, down} -> % no change in interval render_glyph_horizontal(Value, {Cr, Px}, Cx - 1, Spans) end. bit_spin(Value, Cx) -> <<_:Cx, Bit:1, _/bits>> = Value, case Bit of 1 -> up; 0 -> down end.