Fix for Issue #8 and Issue #6

Resolves incomplete padding on multi-ecc blocks resulting in atoms in
final bitmap
Should cope with all circumstances.
Also exposes encode/2
This commit is contained in:
Steven Charles Davis 2015-12-21 17:41:50 -06:00
parent e96022ac4f
commit 9da3a8d73c

View File

@ -17,7 +17,7 @@
-include("qrcode.hrl"). -include("qrcode.hrl").
-include("qrcode_params.hrl"). -include("qrcode_params.hrl").
-export([encode/1, decode/1]). -export([encode/1, encode/2, decode/1]).
%% %%
decode(_Bin) -> decode(_Bin) ->
@ -76,22 +76,42 @@ encode_content(byte, Version, Bin) ->
%% %%
generate_ecc_blocks(#qr_params{block_defs = ECCBlockDefs}, Bin) -> generate_ecc_blocks(#qr_params{block_defs = ECCBlockDefs}, Bin) ->
generate_ecc(Bin, ECCBlockDefs, []). Bin0 = pad_data(Bin, ECCBlockDefs),
% generate_ecc(Bin0, ECCBlockDefs, []).
pad_data(Bin, ECCBlockDefs) ->
DataSize = byte_size(Bin),
TotalSize = get_ecc_size(ECCBlockDefs),
PaddingSize = TotalSize - DataSize,
Padding = binary:copy(<<?DATA_PAD_0, ?DATA_PAD_1>>, PaddingSize bsr 1),
case PaddingSize band 1 of
0 ->
<<Bin/binary, Padding/binary>>;
1 ->
<<Bin/binary, Padding/binary, ?DATA_PAD_0>>
end.
get_ecc_size(ECCBlockDefs) ->
get_ecc_size(ECCBlockDefs, 0).
get_ecc_size([{C, _, D}|T], Acc) ->
get_ecc_size(T, C * D + Acc);
get_ecc_size([], Acc) ->
Acc.
generate_ecc(Bin, [{C, L, D}|T], Acc) -> generate_ecc(Bin, [{C, L, D}|T], Acc) ->
{Result, Bin0} = generate_ecc0(Bin, C, L, D, []), {Result, Bin0} = generate_ecc0(Bin, C, L, D, []),
generate_ecc(Bin0, T, [Result|Acc]); generate_ecc(Bin0, T, [Result|Acc]);
generate_ecc(<<>>, [], Acc) -> generate_ecc(<<>>, [], Acc) ->
lists:flatten(lists:reverse(Acc)). lists:flatten(lists:reverse(Acc)).
%
generate_ecc0(Bin, Count, TotalLength, BlockLength, Acc) when byte_size(Bin) >= BlockLength, Count > 0 -> generate_ecc0(Bin, Count, TotalLength, BlockLength, Acc) when byte_size(Bin) >= BlockLength, Count > 0 ->
<<Block:BlockLength/binary, Bin0/binary>> = Bin, <<Block:BlockLength/binary, Bin0/binary>> = Bin,
EC = qrcode_reedsolomon:encode(Block, TotalLength - BlockLength), EC = qrcode_reedsolomon:encode(Block, TotalLength - BlockLength),
generate_ecc0(Bin0, Count - 1, TotalLength, BlockLength, [{Block, EC}|Acc]); generate_ecc0(Bin0, Count - 1, TotalLength, BlockLength, [{Block, EC}|Acc]);
generate_ecc0(Bin, Count, TotalLength, BlockLength, Acc) when Count > 0 ->
Block = pad_block(Bin, BlockLength),
EC = qrcode_reedsolomon:encode(Block, TotalLength - BlockLength),
{lists:reverse([{Block, EC}|Acc]), <<>>};
generate_ecc0(Bin, 0, _, _, Acc) -> generate_ecc0(Bin, 0, _, _, Acc) ->
{lists:reverse(Acc), Bin}. {lists:reverse(Acc), Bin}.
@ -121,17 +141,7 @@ encode_bytes(Version, Bin) when is_binary(Bin) ->
Size = size(Bin), Size = size(Bin),
CharacterCountBitSize = cci(?BYTE_MODE, Version), CharacterCountBitSize = cci(?BYTE_MODE, Version),
<<?BYTE_MODE:4, Size:CharacterCountBitSize, Bin/binary, 0:4>>. <<?BYTE_MODE:4, Size:CharacterCountBitSize, Bin/binary, 0:4>>.
%
pad_block(Bin, BlockLength) ->
PadCount = BlockLength - byte_size(Bin),
Pad = binary:copy(<<?DATA_PAD_0, ?DATA_PAD_1>>, PadCount bsr 1),
case PadCount band 1 of
0 ->
Padding = Pad;
1 ->
Padding = <<Pad/binary, ?DATA_PAD_0>>
end,
<<Bin/binary, Padding/binary>>.
%% Table 25. Error correction level indicators %% Table 25. Error correction level indicators
ecc('L') -> 1; ecc('L') -> 1;
@ -191,4 +201,3 @@ format_info_bits(#qr_params{ec_level = ECLevel, mask = MaskType}) ->
InfoWithEC = (Info bsl 10) bor BCH, InfoWithEC = (Info bsl 10) bor BCH,
Value = InfoWithEC bxor ?FORMAT_INFO_MASK, Value = InfoWithEC bxor ?FORMAT_INFO_MASK,
<<Value:15>>. <<Value:15>>.