首先是點陣字的概念:點陣字型是把每一個字元都分成 n * n 個點,然後用每個點的虛實來表示字元的輪廓。點陣字型也叫位圖字型,其中每個字形都以一組二維像素資訊表示。
漢字那麼多,總不能每個字都去自己設計點陣吧?别擔心,有現成的點陣字庫可以直接使用:HZK16字庫。HZK即漢字庫的首字母縮寫,HZK16字庫是符合GB2312标準的16×16點陣字庫,支援的漢字有6763個(但可惜不支援英文和數字),每個漢字模型需要16×16一共需要256個點來顯示。
這樣思路就出來了:我們自己輸入漢字,根據字元串中漢字字元編碼,去HZK16字庫中擷取點陣資訊,拿到資訊後根據16*16點陣每個點的資料,print 出不同字元。
- 擷取微信好友頭像生成點陣圖檔代碼
# -*- coding:utf-8 -*-
import binascii,os,itchat
from PIL import Image
def char2bit(textStr):
KEYS = [0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01]
target = []
global count
count = 0
for x in range(len(textStr)):
text = textStr[x]
rect_list = [] * 16
for i in range(16):
rect_list.append([] * 16)
gb2312 = text.encode('gb2312')
hex_str = binascii.b2a_hex(gb2312)#字元串轉16進制
result = str(hex_str, encoding='utf-8')
area = eval('0x' + result[:2]) - 0xA0
index = eval('0x' + result[2:]) - 0xA0
offset = (94 * (area-1) + (index-1)) * 32
font_rect = None
with open("HZK16", "rb") as f:
f.seek(offset)
font_rect = f.read(32)
for k in range(len(font_rect) // 2):
row_list = rect_list[k]
for j in range(2):
for i in range(8):
asc = font_rect[k * 2 + j]
flag = asc & KEYS[i]
row_list.append(flag)
output = []
for row in rect_list:
for i in row:
if i:
output.append('1')
count+=1
#print('0', end=' ')
else:
output.append('0')
#print('.', end=' ')
#print()
target.append(''.join(output))
return target
def getHeadImgs():
#通過二維碼登入微信網頁版
itchat.auto_login()
#擷取微信好友資訊清單
friendList = itchat.get_friends(update=True)
#這裡會用到的微信好友資訊如下: User= {'UserName': '@8238e922e8be7356b1750c306cb75768','PYQuanPin': 'TED','NickName': 'TED'}
#擷取使用者個人昵稱,用于之後檔案夾命名、使用者頭像命名
if friendList[0]['PYQuanPin']:
user = friendList[0]['PYQuanPin']
else:
user = friendList[0]['NickName']
#先讀取使用者本人頭像,存儲名為使用者名稱
selfHead = "{}/{}.jpg".format(os.getcwd(),user)
with open(selfHead,'wb') as f:
head = itchat.get_head_img(friendList[0]['UserName'])
f.write(head)
#建立檔案夾用于存儲好友頭像
if not os.path.exists(user):
os.mkdir(user)
#工作路徑轉到建立檔案夾中
os.chdir(user)
#擷取建立檔案夾路徑
userspace = os.getcwd()
#開始讀取好友頭像寫入建立檔案夾中
print("開始讀取%d位好友頭像..."%(len(friendList)-1))
for i in range(1,len(friendList)):
if i % 100 ==0:
print("已讀取%d位好友頭像,請耐心等待~"%i)
try:
friendList[i]['head_img'] = itchat.get_head_img(userName=friendList[i]['UserName'])
friendList[i]['head_img_name'] = "%s.jpg" % friendList[i]['UserName']
except ConnectionError:
print('Fail to get %s' % friendList[i]['UserName'])
with open(friendList[i]['head_img_name'],'wb') as f:
f.write(friendList[i]['head_img'])
print("讀取好友頭像完畢!")
#儲存頭像的檔案夾路徑和使用者本人頭像路徑傳回
return user, selfHead
def head2char(workspace,user,self,outlist):
folder = "{}\\{}".format(workspace,user)
#将工作路徑轉移至頭像檔案夾
os.chdir(folder)
#擷取檔案夾内頭像清單
imgList = os.listdir(folder)
#擷取頭像圖檔個數
numImages = len(imgList)
#設定頭像裁剪後尺寸
eachSize = 100
#變量n用于循環周遊頭像圖檔,即當所需圖檔大于頭像總數時,循環使用頭像圖檔
n=0
#變量count用于為最終生成的單字圖檔編号
count = 0
#img = Image.open(self)
#初始化顔色清單,用于背景着色:FFFACD黃色 #F0FFFF白 #BFEFFF 藍 #b7facd青色 #ffe7cc淺橙色 #fbccff淺紫色 #d1ffb8淡綠 #febec0淡紅 #E0EEE0灰
colorlist = ['#FFFACD','#F0FFFF','#BFEFFF','#b7facd','#ffe7cc','#fbccff','#d1ffb8','#febec0','#E0EEE0']
#index用來改變不同字的背景顔色
index = 0
#每個item對應不同字的點陣資訊
for item in outlist:
#将工作路徑轉到頭像所在檔案夾
os.chdir(folder)
#建立一個帶有背景色的畫布,16*16點陣,每個點處填充2*2張頭像圖檔,故長為16*2*100
#如果想要白色背景,将colorlist[index]改為'#FFFFFF'
canvas = Image.new('RGB', (3200, 3200), colorlist[index]) # 建立一塊畫布
#index變換,用于變換背景顔色
index = (index+1)%9
count += 1
#每個16*16點陣中的點,用四張100*100的頭像來填充
for i in range(16*16):
#點陣資訊為1,即代表此處要顯示頭像來組字
if item[i] == "1":
#循環讀取連續的四張頭像圖檔
x1 = n % len(imgList)
x2 = (n+1) % len(imgList)
x3 = (n+2) % len(imgList)
x4 = (n+3) % len(imgList)
#以下四組try,将讀取到的四張頭像填充到畫闆上對應的一個點位置
#點陣處左上角圖檔1/4
try:
img = Image.open(imgList[x1]) # 打開圖檔
except IOError:
print("有1位朋友的頭像讀取失敗,已使用本人頭像替代") # 有些人沒設定頭像,就會有異常
img = Image.open(self)
finally:
img = img.resize((eachSize, eachSize), Image.ANTIALIAS) # 縮小圖檔
canvas.paste(img, ((i % 16) * 2 * eachSize, (i // 16) * 2 * eachSize)) # 拼接圖檔
# 點陣處右上角圖檔2/4
try:
img = Image.open(imgList[x2]) # 打開圖檔
except IOError:
print("有1位朋友的頭像讀取失敗,已使用本人頭像替代") # 有些人沒設定頭像,就會有異常
img = Image.open(self)
finally:
img = img.resize((eachSize, eachSize), Image.ANTIALIAS) # 縮小圖檔
canvas.paste(img, (((i % 16) * 2 + 1) * eachSize, (i // 16) * 2 * eachSize)) # 拼接圖檔
# 點陣處左下角圖檔3/4
try:
img = Image.open(imgList[x3]) # 打開圖檔
except IOError:
print("有1位朋友的頭像讀取失敗,已使用本人頭像替代") # 有些人沒設定頭像,就會有異常
img = Image.open(self)
finally:
img = img.resize((eachSize, eachSize), Image.ANTIALIAS) # 縮小圖檔
canvas.paste(img, ((i % 16) * 2 * eachSize, ((i // 16) * 2 + 1 ) * eachSize)) # 拼接圖檔
# 點陣處右下角圖檔4/4
try:
img = Image.open(imgList[x4]) # 打開圖檔
except IOError:
print("有1位朋友的頭像讀取失敗,已使用本人頭像替代") # 有些人沒設定頭像,就會有異常
img = Image.open(self)
finally:
img = img.resize((eachSize, eachSize), Image.ANTIALIAS) # 縮小圖檔
canvas.paste(img, (((i % 16) * 2 + 1) * eachSize, ((i // 16) * 2 + 1) * eachSize)) # 拼接圖檔
#調整n以讀取後續圖檔
n= (n+4) % len(imgList)
os.chdir(workspace)
# 建立檔案夾用于存儲輸出結果
if not os.path.exists('{}_output'.format(user)):
os.mkdir('{}_output'.format(user))
os.chdir('{}_output'.format(user))
#quality代表圖檔品質,1-100
canvas.save('result%d.jpg'% count, quality=100)
if __name__=="__main__":
#将想轉化的字賦給字元串
inpt = "生日快樂,事事順心!"
#将字轉化為漢字庫的點陣資料
outlist = char2bit(inpt)
print(outlist)
#擷取目前檔案夾路徑
workspace = os.getcwd()
#擷取使用者本人名稱和使用者本人頭像路徑
user,self = getHeadImgs()
# #将頭像圖檔按點陣拼接成單字圖檔
head2char(workspace,user,self,outlist)
print("Well done!")
複制
- 根據制定圖檔生成點陣圖檔代碼
# -*- coding:utf-8 -*-
import binascii,os
from PIL import Image
def char2bit(textStr):
KEYS = [0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01]
target = []
global count
count = 0
for x in range(len(textStr)):
text = textStr[x]
rect_list = [] * 16
for i in range(16):
rect_list.append([] * 16)
gb2312 = text.encode('gb2312')
hex_str = binascii.b2a_hex(gb2312)
result = str(hex_str, encoding='utf-8')
area = eval('0x' + result[:2]) - 0xA0
index = eval('0x' + result[2:]) - 0xA0
offset = (94 * (area-1) + (index-1)) * 32
font_rect = None
with open("HZK16", "rb") as f:
f.seek(offset)
font_rect = f.read(32)
for k in range(len(font_rect) // 2):
row_list = rect_list[k]
for j in range(2):
for i in range(8):
asc = font_rect[k * 2 + j]
flag = asc & KEYS[i]
row_list.append(flag)
output = []
for row in rect_list:
for i in row:
if i:
output.append('1')
count+=1
#print('0', end=' ')
else:
output.append('0')
#print('.', end=' ')
#print()
target.append(''.join(output))
return target
def head2char(workspace,folder,self,outlist):
#将工作路徑轉移至頭像檔案夾
os.chdir(folder)
#擷取檔案夾内頭像清單
imgList = os.listdir(folder)
#擷取頭像圖檔個數
numImages = len(imgList)
#設定頭像裁剪後尺寸
eachSize = 100
#變量n用于循環周遊頭像圖檔,即當所需圖檔大于頭像總數時,循環使用頭像圖檔
n=0
#變量count用于為最終生成的單字圖檔編号
count = 0
#img = Image.open(self)
#初始化顔色清單,用于背景着色:FFFACD黃色 #F0FFFF白 #BFEFFF 藍 #b7facd青色 #ffe7cc淺橙色 #fbccff淺紫色 #d1ffb8淡綠 #febec0淡紅 #E0EEE0灰
colorlist = ['#FFFACD','#F0FFFF','#BFEFFF','#b7facd','#ffe7cc','#fbccff','#d1ffb8','#febec0','#E0EEE0']
#index用來改變不同字的背景顔色
index = 0
#每個item對應不同字的點陣資訊
for item in outlist:
#将工作路徑轉到頭像所在檔案夾
os.chdir(folder)
#建立一個帶有背景色的畫布,16*16點陣,每個點處填充2*2張頭像圖檔,故長為16*2*100
#如果想要白色背景,将colorlist[index]改為'#FFFFFF'
canvas = Image.new('RGB', (3200, 3200), colorlist[index]) # 建立一塊畫布
#index變換,用于變換背景顔色
index = (index+1)%9
count += 1
#每個16*16點陣中的點,用四張100*100的頭像來填充
for i in range(16*16):
#點陣資訊為1,即代表此處要顯示頭像來組字
if item[i] == "1":
#循環讀取連續的四張頭像圖檔
x1 = n % len(imgList)
x2 = (n+1) % len(imgList)
x3 = (n+2) % len(imgList)
x4 = (n+3) % len(imgList)
#以下四組try,将讀取到的四張頭像填充到畫闆上對應的一個點位置
#點陣處左上角圖檔1/4
try:
img = Image.open(imgList[x1]) # 打開圖檔
except IOError:
print("有1張圖檔讀取失敗,已使用備用圖像替代")
img = Image.open(self)
finally:
img = img.resize((eachSize, eachSize), Image.ANTIALIAS) # 縮小圖檔
canvas.paste(img, ((i % 16) * 2 * eachSize, (i // 16) * 2 * eachSize)) # 拼接圖檔
# 點陣處右上角圖檔2/4
try:
img = Image.open(imgList[x2]) # 打開圖檔
except IOError:
print("有1張圖檔讀取失敗,已使用備用圖像替代")
img = Image.open(self)
finally:
img = img.resize((eachSize, eachSize), Image.ANTIALIAS) # 縮小圖檔
canvas.paste(img, (((i % 16) * 2 + 1) * eachSize, (i // 16) * 2 * eachSize)) # 拼接圖檔
# 點陣處左下角圖檔3/4
try:
img = Image.open(imgList[x3]) # 打開圖檔
except IOError:
print("有1張圖檔讀取失敗,已使用備用圖像替代")
img = Image.open(self)
finally:
img = img.resize((eachSize, eachSize), Image.ANTIALIAS) # 縮小圖檔
canvas.paste(img, ((i % 16) * 2 * eachSize, ((i // 16) * 2 + 1 ) * eachSize)) # 拼接圖檔
# 點陣處右下角圖檔4/4
try:
img = Image.open(imgList[x4]) # 打開圖檔
except IOError:
print("有1張圖檔讀取失敗,已使用備用圖像替代")
img = Image.open(self)
finally:
img = img.resize((eachSize, eachSize), Image.ANTIALIAS) # 縮小圖檔
canvas.paste(img, (((i % 16) * 2 + 1) * eachSize, ((i // 16) * 2 + 1) * eachSize)) # 拼接圖檔
#調整n以讀取後續圖檔
n= (n+4) % len(imgList)
os.chdir(workspace)
# 建立檔案夾用于存儲輸出結果
if not os.path.exists('{}_輸出'.format(user)):
os.mkdir('{}_輸出'.format(user))
os.chdir('{}_輸出'.format(user))
#存儲将拼接後的圖檔,quality為圖檔品質,1-100,100最高
canvas.save('result%d.jpg'% count, quality=100)
if __name__=="__main__":
#将想轉化的字賦給字元串
inpt = "二零一九新年快樂!"
#将字轉化為漢字庫的點陣資料
outlist = char2bit(inpt)
#擷取目前檔案夾路徑
workspace = os.getcwd()
#用于拼接的圖檔所在檔案夾名稱
user = "周小董"
#擷取圖檔檔案夾所在路徑
folder = "{}\\{}".format(workspace,user)
#若讀取圖檔失敗,用于替代的備用圖檔路徑
self=workspace+"\\"+"周小董.jpg"
#運作後将生成 user_輸出 檔案夾
head2char(workspace,folder,self,outlist)
print("Well done!")
複制
參考:https://my.oschina.net/crossin/blog/3011967
git源碼:https://github.com/pengfexue2/pic2char