模块:沙盒/a2569875/QR
外观
123
require('Module:Module wikitext')._addText('123')
local p={}
local encode_table={}
local libencode = require('Module:EncoderUtil')
local libqrcode = libencode._get_libqrcode()
local lib_arg={}
local ec_level_list={l=1,m=2,q=3,h=4,[0]=1,[1]=1,[2]=2,[3]=3,[4]=4,
low=1,medium=2,quartile=3,high=4
}
local ec_level_table={'low','medium','quartile','high'}
local en_mode_list={n=1,a=2,b=4,k=8,j=8,[0]=0,[1]=1,[2]=2,[4]=4,[4]=8,
numeric=1,alphanumeric=2,byte=4,kanji=8
}
local en_mode_table={'numeric','alphanumeric',[4]='byte',[8]='kanji'}
function _kanjiLen(str,mode)
if mode == 1 then -- numeric
return math.ceil(#str * 10 / 39)
elseif mode == 2 then -- alphanumeric
return math.ceil(#str * 11 / 26)
elseif mode == 4 then -- binary
return math.ceil(#str * 8 / 13)
else
return mw.ustring.len(str)
end
end
--line-height: 12px;
--p.logQR(({p.qrcode_message_bits("1A好2你23", 1, 8, 5)})[2])
function p.logQR(qrTable)
local char_list={
[-2]='▁',
[-1]='▁',
[0]='▁',
[1]='▇',
[2]='▇',
}
local result = ''
for i=1,#qrTable do
result=result..'\n'
for j=1,#(qrTable[i]) do
result=result..char_list[qrTable[j][i]]
end
end
mw.log(result)
end
function p.qrcode_message_bits(str, input_ec_level, input_mode, version_input)
local mode = en_mode_list[input_mode or 0]
local encode_mode, mode_flag = p.checkMode(str,mode)
local encode_len = libencode._get_string_length(str)
local encode_data = {{
mode=encode_mode,
text=str,
len=encode_len
}}
if encode_mode==8 then --kanji
encode_data, encode_len = _data_spilter(str)
end
local requested_ec_level = ec_level_list[input_ec_level or 0]
local version, ec_level = libqrcode.get_version_eclevel(encode_len,encode_mode,requested_ec_level)
local check_ver = tonumber(version_input or 0)
if check_ver ~= 0 and check_ver < version then mw.addWarning( string.format(
"Version %d 且容錯等級為 %s 的QR碼不足以容納 \"%s\" 。",check_ver,ec_level_table[requested_ec_level],str) ) end
if not mode_flag or mode==nil then mw.addWarning(string.format(
"無法將 \"%s\" 以編碼模式 %s 進行編碼。",str, en_mode_table[mode] or tostring(input_mode) )) end
if check_ver > version then version = check_ver end
local data_raw=''
for i=1,#encode_data do
local item = encode_data[i]
data_raw = data_raw .. _encodeQRdata(item,version)
end
data_raw = libqrcode.add_pad_data(version,ec_level,data_raw)
arranged_data = libqrcode.arrange_codewords_and_calculate_ec(version,ec_level,data_raw)
if math.fmod(#arranged_data,8) ~= 0 then
return false, string.format("Arranged data %% 8 != 0: data length = %d, mod 8 = %d",#arranged_data, math.fmod(#arranged_data,8))
end
arranged_data = arranged_data .. string.rep("0",libqrcode.remainder[version])
local tab = libqrcode.get_matrix_with_lowest_penalty(version,ec_level,arranged_data)
return true, tab, ec_level, encode_mode, version
end
function p.checkMode(str,mode)
local calc_mode=p.getMode(str)
if mode == 1 then -- numeric
return calc_mode, calc_mode == mode
elseif mode == 2 then -- alphanumeric
if mode >= calc_mode then return mode, true end
return calc_mode, false
elseif mode == 4 or mode == 8 then -- binary or kanji
return mode, true
else --default
return calc_mode, false
end
end
function p.getMode(str)
if mw.ustring.match(str,"^[0-9]+$") then
return 1
elseif mw.ustring.match(str,"^[0-9A-Z $%%*./:+-]+$") then
return 2
else
if p.checkJISX0208(str)then
return 8
else
return 4
end
end
end
function _data_spilter(str)
local total_len=0
local code_len=mw.ustring.len(str)
local spilt_result = {}
local buffer, str_mode, check_mode='',0,0
for i=1,code_len do
local unicode,char_it=mw.ustring.codepoint(str,i),mw.ustring.sub(str,i,i)
if not encode_table.shiftJIS then encode_table = mw.loadData('Module:沙盒/a2569875/Test/data')end
if encode_table.shiftJIS[unicode] then check_mode=8
elseif mw.ustring.match(char_it,'[0-9]+') then check_mode=1
elseif mw.ustring.match(char_it,'[0-9A-Z $%%*./:+-]+') then check_mode=2
else check_mode=4 end
if check_mode ~= str_mode then
if buffer~=''then
local buffer_len = _kanjiLen(buffer,str_mode)
total_len = total_len + buffer_len
spilt_result[#spilt_result + 1]={
mode=str_mode,
text=buffer,
len=buffer_len
}
end
buffer=''
end
str_mode = check_mode
buffer = buffer .. char_it
end
if buffer~=''then
local buffer_len = _kanjiLen(buffer,str_mode)
total_len = total_len + buffer_len
spilt_result[#spilt_result + 1]={
mode=str_mode,
text=buffer,
len=buffer_len
}
end
spilt_result[#spilt_result + 1]={mode=0,len=0}
return spilt_result, total_len
end
function p.check_str_mode(str,mode)
if string.match(str,"^[0-9]+$") then
return 1
elseif string.match(str,"^[0-9A-Z $%%*./:+-]+$") then
return 2
else
if p.checkJISX0208(str)then
return 8
else
return 4
end
end
end
function _length_binary(lenth,version,mode)
local i = mode
if mode == 4 then i = 3
elseif mode == 8 then i = 4
end
assert( i <= 4 )
local tab = { {10,9,8,8},{12,11,16,10},{14,13,16,12} }
local digits
if version < 10 then
digits = tab[1][i]
elseif version < 27 then
digits = tab[2][i]
elseif version <= 40 then
digits = tab[3][i]
else
assert(false, "get_length, version > 40 not supported")
end
return libencode._toBinary(lenth,digits)
end
function _encodeQRdata(item, version)
local data_raw=libencode._toBinary((type(item.text)==type(nil))and 0 or item.mode,4)
if type(item.text)~=type(nil) then
if item.mode==8 then
local input_bytes=p.unicode2shiftJISbytes(item.text)
data_raw = data_raw .. _length_binary(#input_bytes,version,item.mode)
for i=1,#input_bytes do data_raw = data_raw .. libencode._toBinary(input_bytes[i],13)end
else
data_raw = data_raw .. libqrcode.get_length((type(item.text)==type(nil))and '' or item.text, version, item.mode)
data_raw = data_raw .. libqrcode.encode_data(item.text,item.mode)
end
else
data_raw = data_raw .. libencode._toBinary(0,4)
end
return data_raw
end
function p.kanjiQR(str,requested_ec_level)
local version, ec_level
local input_bytes, local_mode=p.unicode2shiftJISbytes(str), 8
version, ec_level = libqrcode.get_version_eclevel(#input_bytes,8,requested_ec_level)
local length_string = libqrcode.get_length(input_bytes,version,local_mode)
local arranged_data, data_raw, mode, len_bitstring
version, ec_level, data_raw, mode, len_bitstring = version,ec_level,libencode._toBinary(local_mode,4),local_mode,length_string
data_raw = data_raw .. len_bitstring
for i=1,#input_bytes do data_raw = data_raw .. libencode._toBinary(input_bytes[i],13)end
data_raw = libqrcode.add_pad_data(version,ec_level,data_raw)
arranged_data = libqrcode.arrange_codewords_and_calculate_ec(version,ec_level,data_raw)
if math.fmod(#arranged_data,8) ~= 0 then
return false, string.format("Arranged data %% 8 != 0: data length = %d, mod 8 = %d",#arranged_data, math.fmod(#arranged_data,8))
end
arranged_data = arranged_data .. string.rep("0",libqrcode.remainder[version])
local tab = libqrcode.get_matrix_with_lowest_penalty(version,ec_level,arranged_data)
return true, tab
end
function p.unicode2shiftJISbytes(str)
local code_len=mw.ustring.len(str)
local result={}
local flag=true
for i=1,code_len do
local codebyte=p.byteJISX0208(str,i)
local unicode=mw.ustring.codepoint(str,i)
if codebyte then result[#result+1]=codebyte
else
if (unicode>47 and unicode<58) or (unicode>64 and unicode<91) or (unicode>96 and unicode<123) then
codebyte = unicode + 159 + (unicode>96 and 1 or 0)
end
if codebyte then result[#result+1]=codebyte
else result[#result+1]=8 end
flag = false
--local unistr = '&#'..unicode..';'
--for j=1,#unistr do result[#result+1]=unistr:byte(j)end
end
end
return result
end
function p.checkJISX0208(str)
local code_len=mw.ustring.len(str)
for i=1,code_len do
local unicode=mw.ustring.codepoint(str,i)
if not encode_table.shiftJIS then encode_table = mw.loadData('Module:沙盒/a2569875/Test/data')end
if not encode_table.shiftJIS[unicode] then return false end
end
return true
end
function p.byteJISX0208(str,offsetbyte)
if not encode_table.shiftJIS then encode_table = mw.loadData('Module:沙盒/a2569875/Test/data')end
local str_byte=mw.ustring.codepoint(str,offsetbyte or 1)
local shiftJIS_byte = encode_table.shiftJIS[str_byte]
local qr_byte=shiftJIS_byte
if shiftJIS_byte then
local bitwise=require('bit32')
local high_b=bitwise.rshift(bitwise.band(shiftJIS_byte,0xFF00),8)
local low_b=bitwise.band(shiftJIS_byte,0xFF)
local offset_data=((high_b>=0x81 and high_b<=0x9F) and 1 or((high_b>=0xE0 and high_b<=0xEB) and 2 or 0))
local offset_map = {0x8140,0xC140,[0]=0}
local byte_m = shiftJIS_byte - offset_map[offset_data]
local high_m=bitwise.rshift(bitwise.band(byte_m,0xFF00),8)
local low_m=bitwise.band(byte_m,0xFF)
qr_byte = (high_m * 0xC0) + low_m
end
return qr_byte
end
return p