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:
		@ -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>>.
 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user