aboutsummaryrefslogblamecommitdiffstats
path: root/lib/percept/test/egd_SUITE.erl
blob: 98a265ce616c2fa1e7c36fd1d4e951419acabae6 (plain) (tree)
1
2
3
4
5
6
7
8
9

                   
  
                                                        
  


                                                                   
  






                                                                           
  



                   
                                           

                               
                          



                                                   




                                    
                      
                                 
 


                                 
 
         

                                                
                
                          
 
 

                                              
           
 
                                             
           
 




                                   




                                                                        
                                   
                                                        


                                                            

       
                    
                                            

                                                            


                           










                                                           

                                                           









                                                                                  


                      
                        
                                           
                                                            
                           









                                                              


                       
                                                
 
                                        
 

                                                         
 
                                                                        
 
                         

                      
 
                        
                                                
                                                            

                           


                                      
 





                                                                                                               



                       
                                                             
 
                                            
 

                                                         
 
                                                 
 

                      
 
                   
                                          
                                                            
                           





                                                                                       
                 


                                                             







                                                                    










                                                           
 

                                                         
 

                                                          
 

                                                         
 
                         


                      
                            
                                                   
                                                            
                           







                                                                


                      











































                                                                         


                                                                        
 




                                                    



                                                                                                         







                                                      
 
                                    
                                         

                                      



                                              


                                  
                                        

                                    



                                              


                                  
                                        

                                    



                                              







                                                                        



                    

              
                



                               


                      









                                                     
        


                                           
                                                   
%%
%% %CopyrightBegin%
%%
%% Copyright Ericsson AB 2007-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
%% You may obtain a copy of the License at
%%
%%     http://www.apache.org/licenses/LICENSE-2.0
%%
%% Unless required by applicable law or agreed to in writing, software
%% distributed under the License is distributed on an "AS IS" BASIS,
%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
%% See the License for the specific language governing permissions and
%% limitations under the License.
%%
%% %CopyrightEnd%
%%

-module(egd_SUITE).
-include_lib("common_test/include/ct.hrl").

%% Test server specific exports
-export([all/0, suite/0]).
-export([init_per_suite/1, end_per_suite/1]).
-export([init_per_testcase/2, end_per_testcase/2]).

%% Test cases
-export([image_create_and_destroy/1,
         image_shape/1,
         image_primitives/1,
         image_colors/1,
         image_font/1,
         image_fans/1,
         image_png_compliant/1]).

suite() ->
    [{ct_hooks,[ts_install_cth]},
     {timetrap, {minutes, 1}}].

all() -> 
    [image_create_and_destroy, image_shape,
     image_primitives, image_colors, image_font,
     image_fans,
     image_png_compliant].


init_per_suite(Config) when is_list(Config) ->
    rand:seed(exsplus),
    Config.

end_per_suite(Config) when is_list(Config) ->
    Config.

init_per_testcase(_Case, Config) ->
    [{max_size, 800}|Config].

end_per_testcase(_Case, _Config) ->
    ok.

%%----------------------------------------------------------------------
%% Tests
%%----------------------------------------------------------------------

%% Image creation and destroy test.
image_create_and_destroy(Config) when is_list(Config) ->
    {W,H} = get_size(proplists:get_value(max_size, Config)),
    Image = egd:create(W, H),
    ok = egd:destroy(Image),
    ok.

%% Image color test.
image_colors(Config) when is_list(Config) ->
    {W,H} = get_size(proplists:get_value(max_size, Config)),
    Image = egd:create(W, H),
    put(image_size, {W,H}),

    RGB = get_rgb(),
    Black = egd:color({0,0,0}),
    Red = egd:color({255,0,0}),
    Green = egd:color({0,255,0}),
    Blue = egd:color({0,0,255}),
    Random = egd:color(Image, RGB),

    ok = egd:line(Image, get_point(), get_point(), Random),
    ok = egd:line(Image, get_point(), get_point(), Red),
    ok = egd:line(Image, get_point(), get_point(), Green),
    ok = egd:line(Image, get_point(), get_point(), Black),
    ok = egd:line(Image, get_point(), get_point(), Blue),

    HtmlDefaultNames = [black,silver,gray,white,maroon,red,
                        purple,fuchia,green,lime,olive,yellow,navy,blue,teal,
                        aqua],

    lists:foreach(fun (ColorName) ->
                          Color = egd:color(ColorName),
                          ok    = egd:line(Image, get_point(), get_point(), Color)
                  end, HtmlDefaultNames),

    <<_/binary>>  = egd:render(Image),
    ok = egd:destroy(Image),
    erase(image_size),
    ok.

%% Image shape API test.
image_shape(Config) when is_list(Config) ->
    {W,H} = get_size(proplists:get_value(max_size, Config)),
    put(image_size, {W,H}),
    Im = egd:create(W, H),

    Fgc = egd:color({255,0,0}),

    ok = egd:line(Im, get_point(), get_point(), Fgc),
    ok = egd:rectangle(Im, get_point(), get_point(), Fgc),
    ok = egd:filledEllipse(Im, get_point(), get_point(), Fgc),
    ok = egd:arc(Im, get_point(), get_point(), Fgc),
    ok = egd:arc(Im, get_point(), get_point(), 100, Fgc),

    Pt1 = get_point(),
    Pt2 = get_point(), 

    ok = egd:filledRectangle(Im, Pt1, Pt2, Fgc),

    Bitmap = egd:render(Im, raw_bitmap),

    ok = bitmap_point_has_color(Bitmap, {W,H}, Pt2, Fgc),
    ok = bitmap_point_has_color(Bitmap, {W,H}, Pt1, Fgc),

    <<_/binary>> = egd:render(Im, raw_bitmap, [{render_engine, alpha}]),

    ok = egd:destroy(Im),
    erase(image_size),
    ok.

%% Image shape API test.
image_primitives(Config) when is_list(Config) ->
    {W,H} = get_size(proplists:get_value(max_size, Config)),
    put(image_size, {W,H}),

    Im0 = egd_primitives:create(W, H),
    Fgc = egd:color({25,25,255}),
    Bgc = egd:color({0,250,25}),

    Im1 = lists:foldl(fun ({Function, Arguments}, Im) ->
                              erlang:apply(egd_primitives, Function, [Im|Arguments])
                      end, Im0,
                      [{Fs, [get_point(), get_point(), Bgc]} || Fs <- [line, rectangle, filledEllipse, arc]] ++
                      [{pixel,          [get_point(), Bgc]},
                       {filledTriangle, [get_point(), get_point(), get_point(), Bgc]}]),

    Pt1 = get_point(),
    Pt2 = get_point(), 

    Im2 = egd_primitives:filledRectangle(Im1, Pt1, Pt2, Fgc),

    Bitmap = egd_render:binary(Im2, opaque),

    ok = bitmap_point_has_color(Bitmap, {W,H}, Pt2, Fgc),
    ok = bitmap_point_has_color(Bitmap, {W,H}, Pt1, Fgc),

    <<_/binary>> = egd_render:binary(Im2, alpha),

    erase(image_size),
    ok.

%% Image font test.
image_font(Config) when is_list(Config) ->
    {W,H} = get_size(proplists:get_value(max_size, Config)),
    put(image_size, {W,H}),
    Im = egd:create(W, H),
    Fgc = egd:color({0,130,0}),

    Filename = filename:join([code:priv_dir(percept),"fonts","6x11_latin1.wingsfont"]),
    Font = egd_font:load(Filename),

    % simple text
    ok = egd:text(Im, get_point(), Font, "Hello World", Fgc),
    <<_/binary>> = egd:render(Im, png),

    GlyphStr1   = " !\"#$%&'()*+,-./",            % Codes  32 ->  47
    NumericStr  = "0123456789",                   % Codes  48 ->  57
    GlyphStr2   = ":;<=>?@",                      % Codes  58 ->  64
    AlphaBigStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZ",   % Codes  65 ->  90
    GlyphStr3   = "[\\]^_`",                      % Codes  91 ->  96
    AlphaSmStr  = "abcdefghijklmnopqrstuvwxyz",   % Codes  97 -> 122
    GlyphStr4   = "{|}~",                         % Codes 123 -> 126

    ok = egd:text(Im, get_point(), Font, GlyphStr1, Fgc),
    <<_/binary>> = egd:render(Im, png),

    ok = egd:text(Im, get_point(), Font, NumericStr, Fgc),
    <<_/binary>> = egd:render(Im, png),

    ok = egd:text(Im, get_point(), Font, GlyphStr2, Fgc),
    <<_/binary>> = egd:render(Im, png),

    ok = egd:text(Im, get_point(), Font, AlphaBigStr, Fgc),
    <<_/binary>> = egd:render(Im, png),

    ok = egd:text(Im, get_point(), Font, GlyphStr3, Fgc),
    <<_/binary>> = egd:render(Im, png),

    ok = egd:text(Im, get_point(), Font, AlphaSmStr, Fgc),
    <<_/binary>> = egd:render(Im, png),

    ok = egd:text(Im, get_point(), Font, GlyphStr4, Fgc),
    <<_/binary>> = egd:render(Im, png),

    ok = egd:destroy(Im),
    erase(image_size),
    ok.

%% Image png compliant test.
image_png_compliant(Config) when is_list(Config) ->
    {W,H} = get_size(proplists:get_value(max_size, Config)),
    put(image_size, {W,H}),
    Im = egd:create(W, H),
    Fgc = egd:color({0,0,0}),
    ok = egd:filledRectangle(Im, get_point(), get_point(), Fgc),

    Bin = egd:render(Im, png),
    true = binary_is_png_compliant(Bin),

    ok = egd:destroy(Im),
    erase(image_size),
    ok.

image_fans(Config) when is_list(Config) ->
    W = 1024,
    H = 800,
    Dir = proplists:get_value(priv_dir, Config),

    Fun = fun({F,Args},Im) ->
                  erlang:apply(egd_primitives,F,[Im|Args])
          end,

    %% fan1
    Ops1 = gen_vertical_fan(1,{0,400},egd:color(red),1024,800,-15),
    Ops2 = gen_horizontal_fan(1,{512,800},egd:color(green),1024,0,-15),

    Im0 = egd_primitives:create(W,H),
    Im1 = lists:foldl(Fun, Im0, Ops1 ++ Ops2),
    Bin1 = egd_render:binary(Im1, opaque),
    Png1 = egd_png:binary(W,H,Bin1),

    File1 = filename:join(Dir,"fan1.png"),
    egd:save(Png1,File1),
    ct:log("<p>Image1:<img src=\"~s\" /></p>~n", [File1]),

    %% fan2
    Ops3 = gen_vertical_fan(7,{0,400},egd:color(red),1024,800,-15),
    Ops4 = gen_horizontal_fan(7,{512,800},egd:color(green),1024,0,-15),

    Im2 = lists:foldl(Fun, Im0, Ops3 ++ Ops4),
    Bin2 = egd_render:binary(Im2, opaque),
    Png2 = egd_png:binary(W,H,Bin2),

    File2 = filename:join(Dir,"fan2.png"),
    egd:save(Png2,File2),
    ct:log("<p>Image2:<img src=\"~s\" /></p>~n", [File2]),
    ok.

gen_vertical_fan(Wd,Pt,C,X,Y,Step) when Y > 0 ->
    [{line,[Pt,{X,Y},Wd,C]}|gen_vertical_fan(Wd,Pt,C,X,Y + Step,Step)];
gen_vertical_fan(_,_,_,_,_,_) -> [].

gen_horizontal_fan(Wd,Pt,C,X,Y,Step) when X > 0 ->
    [{line,[Pt,{X,Y},Wd,C]}|gen_horizontal_fan(Wd,Pt,C,X + Step,Y,Step)];
gen_horizontal_fan(_,_,_,_,_,_) -> [].


%%----------------------------------------------------------------------
%% Auxiliary tests
%%----------------------------------------------------------------------

bitmap_point_has_color(Bitmap, {W,_}, {X,Y}, C) ->
    {CR,CG,CB,_} = egd_primitives:rgb_float2byte(C),
    N = W*Y*3 + X*3,
    << _:N/binary, R,G,B, _/binary>> = Bitmap,
    case {R,G,B} of
        {CR,CG,CB} -> ok;
        Other ->
            io:format("bitmap_point_has_color: error color was ~p, should be ~p~n", [Other, {CR,CG,CB}]),
            {error, {Other,{CR,CG,CB}}}
    end.

%% jfif header by specification
%% 2 bytes, length
%% 5 bytes, identifier ="JFIF\0"
%% 2 bytes, version, (major, minor)
%% 1 byte , units
%% However, JFIF seems to start at 6 (7 with 1-index)?

binary_is_jfif_compliant(JpegBin) ->
    {Bin, _} = split_binary(JpegBin, 11),
    List = binary_to_list(Bin),
    case lists:sublist(List, 7, 4) of 
        "JFIF" -> true;
        Other ->
            io:format("img -> ~p~n", [Other]),
            false
    end.

binary_is_gif_compliant(GifBin) ->
    {Bin, _} = split_binary(GifBin, 10),
    List = binary_to_list(Bin),
    case lists:sublist(List, 1,5) of
        "GIF87" -> true;
        Other ->
            io:format("img -> ~p~n", [Other]),
            false
    end.

binary_is_png_compliant(PngBin) ->
    {Bin, _} = split_binary(PngBin, 10),
    List = binary_to_list(Bin),
    case lists:sublist(List, 2,3) of
        "PNG" -> true;
        Other ->
            io:format("img -> ~p~n", [Other]),
            false
    end.

%%----------------------------------------------------------------------
%% Auxiliary
%%----------------------------------------------------------------------


get_rgb() ->
    R = random(255),
    G = random(255),
    B = random(255),
    {R,G,B}.

get_angle() ->
    random(359).

get_point() ->
    get_point(get(image_size)).
get_point({W,H}) ->
    X = random(W - 1),
    Y = random(H - 1),
    {X,Y}.

get_size(Max) ->
    W = trunc(random(Max/2) + Max/2 + 1),
    H = trunc(random(Max/2) + Max/2 + 1),
    io:format("Image size will be ~p x ~p~n", [W,H]),
    {W,H}.

get_points(N) ->
    get_points(N, []).
get_points(0, Out) ->
    Out;
get_points(N, Out) ->
    get_points(N - 1, [get_point() | Out]).

random(N) -> trunc(rand:uniform(trunc(N + 1)) - 1).