Skip to content

Instantly share code, notes, and snippets.

@mokele
Created January 17, 2011 02:56
Show Gist options
  • Save mokele/782431 to your computer and use it in GitHub Desktop.
Save mokele/782431 to your computer and use it in GitHub Desktop.
-module(eimgs).
-compile(export_all).
-define(M,16#FF).
-define(SOI,16#D8).
-define(EOI,16#D9).
-record(jpg, {buf = <<>>}).
go() ->
{ok, IO} = file:open("dat/me.jpg", [read,binary]),
chunk(IO, {#jpg{}, 2, fun marker/2}).
chunk(_IO, ok) ->
ok;
chunk(IO, {I=#jpg{buf=Buf}, Read, Fun}) ->
case read(IO, Buf, Read) of
{ok, Buf2, Data} ->
chunk(IO, Fun(I#jpg{buf=Buf2}, Data));
{error, Reason} ->
io:format("Error: ~p~n", [Reason]);
eof ->
ok
end.
%% read Read number of bytes from either the binary second
%% argument buffer or from the iodevice, or both if there's
%% some but not enough in the binary buffer.
read(IO, <<>>, Read) ->
%% shortcut for no buffer, go straight to file
read_response(file:read(IO,Read));
read(IO, Buf, Read) ->
{Buf2,BufRead,Count} = bin_read(Buf,Read),
read(IO, Buf2, Read, BufRead, Count).
read(_IO, Buf, Read, Acc, Read) ->
{ok,Buf,Acc};
read(IO, Buf, Read, Acc, Count) ->
case file:read(IO,Read-Count) of
{ok, Data} ->
{ok,Buf,<<Acc/binary,Data/binary>>};
{error, Reason} ->
{error, Reason};
eof ->
case Acc of
<<>> -> eof;
_ -> {ok,Buf,Acc}
end
end.
read_response({ok, Data}) -> {ok, <<>>, Data};
read_response(Other) -> Other.
%% bin_read
bin_read(Buf,Read) ->
bin_read(Buf,Read,<<>>,0).
bin_read(<<>>,_Read,Acc,Count) ->
{<<>>,Acc,Count};
bin_read(Rest,Read,Acc,Read) ->
{Rest,Acc,Read};
bin_read(<<Byte:8,Rest/binary>>,Read,Acc,Count) ->
bin_read(Rest,Read,<<Acc/binary,Byte:8>>,Count+1).
%% 11,648 bytes
%% start of image SOI
marker(I, <<?M,?SOI>>) ->
io:format("Start of image...~n"),
{I, 2, fun marker/2};
%% end of image EOI
marker(I, <<?M,?EOI>>) ->
io:format("End of image!~n"),
{I, 2, fun marker/2};
marker(I, <<?M,16#DA>>) ->
io:format("Stat of scan...~n"),
{I, 3, fun scan_length/2};
marker(I, <<?M,Marker:8>>) ->
io:format("Marker: ~p~n", [marker(Marker)]),
{I, 2, fun marker_segment_length/2}.
marker_segment_length(I, <<Length:2/integer-unsigned-unit:8>>) ->
{I, Length-2, fun marker_segment/2}.
marker_segment(I, _Data) ->
%io:format("Data: ~p~n", [Data]),
{I, 2, fun marker/2}.
scan_length(I, <<Length:2/integer-unsigned-unit:8,Ns:1/integer-unsigned-unit:8>>) ->
io:format("Ns: ~p~n", [Ns]),
{I, Length, fun scan_header/2}.
scan_header(I, Data) ->
io:format("Scan Header: ~p~n", [Data]),
{I, 3, fun scan/2}.
scan(I, <<Ss:8,Se:8,Ah:4,Al:4>>) ->
io:format("Scan: ~p ~p ~p ~p~n", [Ss,Se,Ah,Al]),
io:format("Entropy "),
{I, 1, fun entropy/2}.
entropy(I, <<?M>>) ->
{I, 1, fun entropy_end_check/2};
entropy(I, _Data) ->
{I, 1, fun entropy/2}.
entropy_end_check(I, <<0:8>>) ->
%% not end of entropy, need to include original ?M in data already read
io:format("Zero Pad "),
{I, 1, fun entropy/2};
entropy_end_check(I=#jpg{buf=Buf}, Other) ->
io:format("~nEnd of entropy~n"),
{I#jpg{buf = <<Buf/binary,?M,Other/binary>>}, 2, fun marker/2}.
marker(16#C0) -> "SOF 0";
marker(16#C1) -> "SOF 1";
marker(16#C2) -> "SOF 2";
marker(16#C3) -> "SOF 3";
marker(16#C5) -> "SOF 5";
marker(16#C6) -> "SOF 6";
marker(16#C7) -> "SOF 7";
marker(16#C8) -> "JPG";
marker(16#C9) -> "SOF 9";
marker(16#CA) -> "SOF 10";
marker(16#CB) -> "SOF 11";
marker(16#CD) -> "SOF 13";
marker(16#CE) -> "SOF 14";
marker(16#CF) -> "SOF 15";
marker(16#C4) -> "DHT";
marker(16#CC) -> "DAC";
marker(M) when M >= 16#D0, M =< 16#D7 -> "DAC";
marker(?SOI) -> "SOI*";
marker(?EOI) -> "EOI*";
marker(16#DA) -> "SOS";
marker(16#DB) -> "DQT";
marker(16#DC) -> "DNL";
marker(16#DD) -> "DRI";
marker(16#DE) -> "DHP";
marker(16#DF) -> "EXP";
marker(M) when M >= 16#E0, M =< 16#EF -> "APPn";
marker(M) when M >= 16#F0, M =< 16#FD -> "JPGn";
marker(16#FE) -> "COM";
marker(16#01) -> "TEM*";
marker(M) when M >= 16#02, M =< 16#BF -> "RES".
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment