Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/processone/ejabberd.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEvgeniy Khramtsov <ekhramtsov@process-one.net>2017-09-25 12:41:12 +0300
committerEvgeniy Khramtsov <ekhramtsov@process-one.net>2017-09-25 12:41:12 +0300
commit3e987d3bae41ac1758c0f12cb061df77ffb444d6 (patch)
treeb1cf1c94d8f2a5aa39024b9ecfee2655f3bde268
parent138cc2535586311ef9ab20cbdd5c30210836890b (diff)
Use eimp instead of ImageMagick calls for thumbnails creation
-rw-r--r--rebar.config2
-rw-r--r--src/misc.erl8
-rw-r--r--src/mod_avatar.erl8
-rw-r--r--src/mod_http_upload.erl113
4 files changed, 71 insertions, 60 deletions
diff --git a/rebar.config b/rebar.config
index 0e8213cae..f1d96bae2 100644
--- a/rebar.config
+++ b/rebar.config
@@ -44,7 +44,7 @@
{tag, "1.0.2"}}}},
{if_var_true, riak, {riakc, ".*", {git, "https://github.com/processone/riak-erlang-client.git",
{tag, "2.5.3"}}}},
- {if_var_true, graphics, {eimp, ".*", {git, "https://github.com/processone/eimp.git", "dc5bfe0"}}},
+ {if_var_true, graphics, {eimp, ".*", {git, "https://github.com/processone/eimp.git", "685d2a2c9b"}}},
%% Elixir support, needed to run tests
{if_var_true, elixir, {elixir, ".*", {git, "https://github.com/elixir-lang/elixir",
{tag, {if_version_above, "17", "v1.4.4", "v1.1.1"}}}}},
diff --git a/src/misc.erl b/src/misc.erl
index 32699e76b..06d81cb88 100644
--- a/src/misc.erl
+++ b/src/misc.erl
@@ -33,7 +33,7 @@
atom_to_binary/1, binary_to_atom/1, tuple_to_binary/1,
l2i/1, i2l/1, i2l/2, expr_to_term/1, term_to_expr/1,
now_to_usec/1, usec_to_now/1, encode_pid/1, decode_pid/2,
- compile_exprs/2, join_atoms/2, try_read_file/1]).
+ compile_exprs/2, join_atoms/2, try_read_file/1, have_eimp/0]).
%% Deprecated functions
-export([decode_base64/1, encode_base64/1]).
@@ -213,6 +213,12 @@ try_read_file(Path) ->
erlang:error(badarg)
end.
+-ifdef(GRAPHICS).
+have_eimp() -> true.
+-else.
+have_eimp() -> false.
+-endif.
+
%%%===================================================================
%%% Internal functions
%%%===================================================================
diff --git a/src/mod_avatar.erl b/src/mod_avatar.erl
index 4d91e1fb9..dde58abf1 100644
--- a/src/mod_avatar.erl
+++ b/src/mod_avatar.erl
@@ -38,7 +38,7 @@
%%% API
%%%===================================================================
start(Host, _Opts) ->
- case have_eimp() of
+ case misc:have_eimp() of
true ->
ejabberd_hooks:add(pubsub_publish_item, Host, ?MODULE,
pubsub_publish_item, 50),
@@ -416,12 +416,6 @@ decode_mime_type(MimeType) ->
encode_mime_type(Type) ->
<<"image/", (atom_to_binary(Type, latin1))/binary>>.
--ifdef(GRAPHICS).
-have_eimp() -> true.
--else.
-have_eimp() -> false.
--endif.
-
mod_opt_type({convert, png}) ->
fun(jpeg) -> jpeg;
(webp) -> webp;
diff --git a/src/mod_http_upload.erl b/src/mod_http_upload.erl
index f117434ed..56c05dc35 100644
--- a/src/mod_http_upload.erl
+++ b/src/mod_http_upload.erl
@@ -25,7 +25,7 @@
-module(mod_http_upload).
-author('holger@zedat.fu-berlin.de').
-
+-compile(export_all).
-protocol({xep, 363, '0.1'}).
-define(SERVICE_REQUEST_TIMEOUT, 5000). % 5 seconds.
@@ -110,7 +110,7 @@
slots = #{} :: map()}).
-record(media_info,
- {type :: binary(),
+ {type :: atom(),
height :: integer(),
width :: integer()}).
@@ -236,12 +236,14 @@ init([ServerHost, Opts]) ->
end,
case Thumbnail of
true ->
- case string:str(os:cmd("identify"), "Magick") of
- 0 ->
- ?ERROR_MSG("Cannot find 'identify' command, please install "
- "ImageMagick or disable thumbnail creation", []);
- _ ->
- ok
+ case misc:have_eimp() of
+ false ->
+ ?ERROR_MSG("ejabberd is built without graphics support, "
+ "please rebuild it with --enable-graphics or "
+ "set 'thumbnail: false' for module '~s' in "
+ "ejabberd.yml", [?MODULE]);
+ _ ->
+ ok
end;
false ->
ok
@@ -726,15 +728,15 @@ parse_http_request(#request{host = Host, path = Path}) ->
store_file(Path, Data, FileMode, DirMode, GetPrefix, Slot, Thumbnail) ->
case do_store_file(Path, Data, FileMode, DirMode) of
ok when Thumbnail ->
- case identify(Path) of
+ case identify(Path, Data) of
{ok, MediaInfo} ->
- case convert(Path, MediaInfo) of
- {ok, OutPath} ->
+ case convert(Path, Data, MediaInfo) of
+ {ok, OutPath, OutMediaInfo} ->
[UserDir, RandDir | _] = Slot,
FileName = filename:basename(OutPath),
URL = str:join([GetPrefix, UserDir,
RandDir, FileName], <<$/>>),
- ThumbEl = thumb_el(OutPath, URL),
+ ThumbEl = thumb_el(OutMediaInfo, URL),
{ok,
[{<<"Content-Type">>,
<<"text/xml; charset=utf-8">>}],
@@ -830,59 +832,68 @@ code_to_message(_Code) -> <<"">>.
%% Image manipulation stuff.
%%--------------------------------------------------------------------
--spec identify(binary()) -> {ok, media_info()} | pass.
-
-identify(Path) ->
- Cmd = io_lib:format("identify -format 'ok %m %h %w' ~s", [Path]),
- Res = string:strip(os:cmd(Cmd), right, $\n),
- case string:tokens(Res, " ") of
- ["ok", T, H, W] ->
- {ok, #media_info{type = list_to_binary(string:to_lower(T)),
- height = list_to_integer(H),
- width = list_to_integer(W)}};
- _ ->
- ?DEBUG("Cannot identify type of ~s: ~s", [Path, Res]),
+-spec identify(binary(), binary()) -> {ok, media_info()} | pass.
+
+identify(Path, Data) ->
+ case misc:have_eimp() of
+ true ->
+ case eimp:identify(Data) of
+ {ok, Info} ->
+ {ok, #media_info{
+ type = proplists:get_value(type, Info),
+ width = proplists:get_value(width, Info),
+ height = proplists:get_value(height, Info)}};
+ {error, Why} ->
+ ?DEBUG("Cannot identify type of ~s: ~s",
+ [Path, eimp:format_error(Why)]),
+ pass
+ end;
+ false ->
pass
end.
--spec convert(binary(), media_info()) -> {ok, binary()} | pass.
+-spec convert(binary(), binary(), media_info()) -> {ok, binary(), media_info()} | pass.
-convert(Path, #media_info{type = T, width = W, height = H}) ->
+convert(Path, Data, #media_info{type = T, width = W, height = H} = Info) ->
if W * H >= 25000000 ->
?DEBUG("The image ~s is more than 25 Mpix", [Path]),
pass;
W =< 300, H =< 300 ->
- {ok, Path};
- T == <<"gif">>; T == <<"jpeg">>; T == <<"png">>; T == <<"webp">> ->
+ {ok, Path, Info};
+ true ->
Dir = filename:dirname(Path),
- FileName = <<(randoms:get_string())/binary, $., T/binary>>,
+ Ext = atom_to_binary(T, latin1),
+ FileName = <<(randoms:get_string())/binary, $., Ext/binary>>,
OutPath = filename:join(Dir, FileName),
- Cmd = io_lib:format("convert -resize 300 ~s ~s", [Path, OutPath]),
- case os:cmd(Cmd) of
- "" ->
- {ok, OutPath};
- Err ->
+ {W1, H1} = if W > H -> {300, round(H*300/W)};
+ H > W -> {round(W*300/H), 300};
+ true -> {300, 300}
+ end,
+ OutInfo = #media_info{type = T, width = W1, height = H1},
+ case eimp:convert(Data, T, [{scale, {W1, H1}}]) of
+ {ok, OutData} ->
+ case file:write_file(OutPath, OutData) of
+ ok ->
+ {ok, OutPath, OutInfo};
+ {error, Why} ->
+ ?ERROR_MSG("Failed to write to ~s: ~s",
+ [OutPath, file:format_error(Why)]),
+ pass
+ end;
+ {error, Why} ->
?ERROR_MSG("Failed to convert ~s to ~s: ~s",
- [Path, OutPath, string:strip(Err, right, $\n)]),
+ [Path, OutPath, eimp:format_error(Why)]),
pass
- end;
- true ->
- ?DEBUG("Won't call 'convert' for unknown type ~s", [T]),
- pass
+ end
end.
--spec thumb_el(binary(), binary()) -> xmlel().
-
-thumb_el(Path, URI) ->
- ContentType = guess_content_type(Path),
- xmpp:encode(
- case identify(Path) of
- {ok, #media_info{height = H, width = W}} ->
- #thumbnail{'media-type' = ContentType, uri = URI,
- height = H, width = W};
- pass ->
- #thumbnail{uri = URI, 'media-type' = ContentType}
- end).
+-spec thumb_el(media_info(), binary()) -> xmlel().
+
+thumb_el(#media_info{type = T, height = H, width = W}, URI) ->
+ MimeType = <<"image/", (atom_to_binary(T, latin1))/binary>>,
+ Thumb = #thumbnail{'media-type' = MimeType, uri = URI,
+ height = H, width = W},
+ xmpp:encode(Thumb).
%%--------------------------------------------------------------------
%% Remove user.