Current section
Files
Jump to
Current section
Files
src/glexif.erl
-module(glexif).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/glexif.gleam").
-export([get_exif_data_for_file/1, error_to_string/1]).
-export_type([exif_error/0]).
-if(?OTP_RELEASE >= 27).
-define(MODULEDOC(Str), -moduledoc(Str)).
-define(DOC(Str), -doc(Str)).
-else.
-define(MODULEDOC(Str), -compile([])).
-define(DOC(Str), -compile([])).
-endif.
?MODULEDOC(" Read standard EXIF metadata from JPEG APP1 segments.\n").
-type exif_error() :: {file_open_error, binary()} |
{file_read_error, binary()} |
{file_close_error, binary()} |
invalid_jpeg_header |
exif_marker_not_found |
unexpected_end_of_file |
{invalid_segment_size, integer()} |
invalid_exif_header |
invalid_tiff_header |
{invalid_entry, integer()} |
{invalid_offset, integer()} |
{offset_cycle, integer()} |
traversal_limit_exceeded.
-file("src/glexif.gleam", 80).
-spec parse_error(glexif@internal@raw:exif_parse_error()) -> exif_error().
parse_error(Error) ->
case Error of
{stream_read_error, Error@1} ->
{file_read_error, file_streams@file_stream_error:describe(Error@1)};
exif_marker_not_found ->
exif_marker_not_found;
unexpected_end_of_file ->
unexpected_end_of_file;
invalid_jpeg_header ->
invalid_jpeg_header;
{invalid_segment_size, Size} ->
{invalid_segment_size, Size};
invalid_exif_header ->
invalid_exif_header;
invalid_tiff_header ->
invalid_tiff_header;
{invalid_entry, Offset} ->
{invalid_entry, Offset};
{invalid_offset, Offset@1} ->
{invalid_offset, Offset@1};
{offset_cycle, Offset@2} ->
{offset_cycle, Offset@2};
traversal_limit_exceeded ->
traversal_limit_exceeded
end.
-file("src/glexif.gleam", 71).
-spec result_map_parse_error(
{ok, glexif@exif_tag:exif_tag_record()} |
{error, glexif@internal@raw:exif_parse_error()}
) -> {ok, glexif@exif_tag:exif_tag_record()} | {error, exif_error()}.
result_map_parse_error(Result) ->
case Result of
{ok, Record} ->
{ok, Record};
{error, Error} ->
{error, parse_error(Error)}
end.
-file("src/glexif.gleam", 47).
?DOC(
" Read EXIF metadata from a JPEG file without panicking for invalid input.\n"
"\n"
" A readable JPEG with no `Exif`-prefixed APP1 candidate returns\n"
" `Error(ExifMarkerNotFound)`. A malformed candidate returns the applicable\n"
" EXIF or TIFF error instead.\n"
).
-spec get_exif_data_for_file(binary()) -> {ok,
glexif@exif_tag:exif_tag_record()} |
{error, exif_error()}.
get_exif_data_for_file(File_path) ->
case file_streams@file_stream:open_read(File_path) of
{error, Error} ->
{error,
{file_open_error,
file_streams@file_stream_error:describe(Error)}};
{ok, Stream} ->
Outcome = case glexif@internal@raw:read_exif_segment(Stream) of
{error, Error@1} ->
{error, parse_error(Error@1)};
{ok, Segment} ->
_pipe = glexif@internal@raw:parse_exif_data_as_record(
Segment
),
result_map_parse_error(_pipe)
end,
Close_outcome = file_streams@file_stream:close(Stream),
case {Outcome, Close_outcome} of
{{error, Error@2}, _} ->
{error, Error@2};
{{ok, _}, {error, Error@3}} ->
{error,
{file_close_error,
file_streams@file_stream_error:describe(Error@3)}};
{{ok, Record}, {ok, nil}} ->
{ok, Record}
end
end.
-file("src/glexif.gleam", 98).
?DOC(" Format an EXIF error for logs or user-facing diagnostics.\n").
-spec error_to_string(exif_error()) -> binary().
error_to_string(Error) ->
case Error of
{file_open_error, Message} ->
<<"Could not open file: "/utf8, Message/binary>>;
{file_read_error, Message@1} ->
<<"Could not read file: "/utf8, Message@1/binary>>;
{file_close_error, Message@2} ->
<<"Could not close file: "/utf8, Message@2/binary>>;
invalid_jpeg_header ->
<<"Invalid JPEG header"/utf8>>;
exif_marker_not_found ->
<<"No EXIF APP1 segment was found"/utf8>>;
unexpected_end_of_file ->
<<"Unexpected end of file"/utf8>>;
{invalid_segment_size, Size} ->
<<"Invalid JPEG segment size: "/utf8,
(erlang:integer_to_binary(Size))/binary>>;
invalid_exif_header ->
<<"Invalid EXIF header"/utf8>>;
invalid_tiff_header ->
<<"Invalid TIFF header"/utf8>>;
{invalid_entry, Offset} ->
<<"Invalid TIFF entry at offset "/utf8,
(erlang:integer_to_binary(Offset))/binary>>;
{invalid_offset, Offset@1} ->
<<"Invalid TIFF offset: "/utf8,
(erlang:integer_to_binary(Offset@1))/binary>>;
{offset_cycle, Offset@2} ->
<<"TIFF offset cycle detected at "/utf8,
(erlang:integer_to_binary(Offset@2))/binary>>;
traversal_limit_exceeded ->
<<"TIFF traversal limit exceeded"/utf8>>
end.