摘要:大家還記得上一篇文章來學點吧從一個斗圖小工具開始中最后提到的幾個問題么,我們這次就來解決一下其中難度最大的一個文本居中看,我把代碼優化了上次之后,我偷偷把代碼優化了,現在的方法長這樣創建表情圖調試用生成表情包對的,我把那些老長老長
大家還記得上一篇文章0.來學點Python吧!從一個斗圖小工具開始中最后提到的幾個問題么,我們這次就來解決一下其中難度最大的一個:文本居中!
上次之后,我偷偷把代碼優化了,現在的main方法長這樣:
# -*- coding:utf-8 -*- #__author__ = "akers" from io import BytesIO from PIL import Image, ImageDraw, ImageFont import sys,platform,operators.image,operators.clipboard def main(argv): # 創建表情圖 image = operators.image.draw_emo("./resources/background/pander/default.png", "./resources/face/jgz/laugth.png", argv[1]) output = BytesIO() image.save(output, format="BMP") operators.clipboard.add_bmp(output) image.save("output/facing.png") # 調試用 # plt.figure("生成表情包") # plt.imshow(target) # plt.show() if __name__ == "__main__": main(sys.argv)
對的,我把那些老長老長的代碼藏到別的包里了,下面是一點題外話,順便介紹一下Python的包與模塊
Python的包與模塊以我們重構后的項目為例,一個項目的結構大致如下
python中的包就是一個包含了__init__.py文件的文件夾,包下可有子包
模塊python的模塊就是一個py文件,其中可包括類、函數、變量等等內容
導入包python中使用import關鍵字引入模塊,import的使用分以下幾種
import package[.sub_package].model導入指定的模塊,調用時需使用模塊全名,例如
import operators.image operators.image.draw_emofrom package[.sub_package] import model
導入指定模塊,調用時直接使用模塊名
from operators import image image.draw_emo()import package[.sub_package].model import function
導入模塊中的函數或成員、類、變量等
from operators.image import draw_emo draw_emo()
Python的包跟模塊的內容還有很多,更詳細的就先不贅述了,然后讓我們繼續主題,咳咳
首先,我們來實現文本的居中,我們先來回顧一下我們是如何插入文本的:
#底圖上的10,200位置寫入文字 draw.text((10, 200), argv[1],fill="black", font=font)
text函數的第一個參數需要個元組,而元組中的0、1兩個元素分別代表的x和y的坐標(以像素為單位),那實現居中就很簡單了,我們只需要根據插入文本的具體寬度計算出一個合適的x坐標就可以了。
于是請看大屏幕,啊呸,請看下圖,
從圖中我們可以看到,文本的插入坐標可以用這樣的公式進行計算:(底圖寬-文本寬) / 2,那問題又來了,文本寬我們怎么得到呢?
在PIL中,我們可以用draw.textsize獲取文本所占的大小,返回是個元組:(寬,高),像這樣:
txtSize = draw.textsize(text, imageFont)
所以我們修改一下draw_text方法:對x坐標進行計算
def draw_text_v1(text, image, off_set=200): """強化版繪制文字v1,讓文字在x軸上居中 Args: text: 顯示在圖片上的文本 image: 當前正使用的Image off_set: 縱向偏移量 Returns: Image Raises: """ # 加入文字 # ImageDraw為PIL的繪圖模塊 _DEFAULT_FONT_SIZE = 30 draw = ImageDraw.Draw(image) imageFont = ImageFont.truetype("./resources/msyh.ttc", _DEFAULT_FONT_SIZE) _MAX_TXT_HEIGH = 32 txtSize = draw.textsize(text, imageFont) pos_x = (CONST_IMG_WIDTH - txtSize[0]) / 2 if CONST_IMG_WIDTH > txtSize[0] else 0 print("當前X坐標", pos_x) # 默認顯示位置 pos = (pos_x, off_set) draw.text(pos, text, fill="black", font=imageFont) del draw return image
相信眼尖的強迫癥患者可能會發現,這里面混著一個很奇怪的寫法:
(CONST_IMG_WIDTH - txtSize[0]) / 2 if CONST_IMG_WIDTH > txtSize[0] else 0
這個if跟else是不是有點調皮,其實這個在python 里類似于c語系里的 ? :三目運算符:如果if后的條件成立,則取if前的表達式進行返回,否則取else后的表達式,上面的代碼實際等同于:
CONST_IMG_WIDTH > txtSize[0] ? (CONST_IMG_WIDTH - txtSize[0]) / 2 : 0
這個細節又暴露了Python的哲學:我已經有了if else了,還要? :干嘛,關鍵字的數量也要最簡;而個語法應該也是從C語系轉過來的小伙伴覺得最別扭的語法之一了吧....
好廢話不多說,來讓我們看看效果,很中對不對:
正所謂要精益求精,既然都做了居中,索性把對齊做個參數好了,跟居中一樣的原理,我把左對齊跟右對齊也做了,只需要對draw_text_v1做一點點潤色:
def draw_text_v2(text, image, off_set=(0, 200), allign="center"): """強化版繪制文字v2,左中右,想放哪里放哪里 Args: text: 顯示在圖片上的文本 image: 當前正使用的Image off_set: 偏移量,用于保留最小編劇,(x, y)以像素未單位 allign: 排版,left左對齊,center居中,right右對齊 Returns: Image Raises: """ # 加入文字 # ImageDraw為PIL的繪圖模塊 _DEFAULT_FONT_SIZE = 30 draw = ImageDraw.Draw(image) imageFont = ImageFont.truetype("./resources/msyh.ttc", _DEFAULT_FONT_SIZE) _MAX_TXT_HEIGH = 32 txtSize = draw.textsize(text, imageFont) imageFont = ImageFont.truetype("./resources/msyh.ttc", 30) # 計算x坐標 pos_x = { # 居中對齊 "center": lambda max_width, txt_len, off: (max_width / 2 - txt_len / 2 if max_width > txt_len else 0) + off, # 左對齊 "left": lambda max_width, txt_len, off: (off if max_width > txt_len else 0), # 右對齊 "right": lambda max_width, txt_len, off: (max_width - txt_len if max_width > txt_len else 0) }[allign if allign in ("center", "left", "right") else "center"](CONST_IMG_WIDTH - 2*off_set[0], txtSize[0], off_set[0]) # 默認顯示位置 pos = (pos_x, off_set[1]) # 底圖上的10,200位置寫入文字 draw.text(pos, text, fill="black", font=imageFont) del draw return image
效果好像還不錯:
估計又有眼尖的小伙伴發現有個代碼不對了,怎么pos_x的計算實現是如此的奇葩,我都看不懂了!
pos_x = { # 居中對齊 "center": lambda max_width, txt_len, off: (max_width / 2 - txt_len / 2 if max_width > txt_len else 0) + off, # 左對齊 "left": lambda max_width, txt_len, off: (off if max_width > txt_len else 0), # 右對齊 "right": lambda max_width, txt_len, off: (max_width - txt_len if max_width > txt_len else 0) }[allign if allign in ("center", "left", "right") else "center"](CONST_IMG_WIDTH - 2*off_set[0], txtSize[0], off_set[0])
其實這里嘛,是Python實現switch功能的一個奇技淫巧...對的,你猜的沒錯,Python是沒有switch結構的,因為:“我們已經有了完美的if...else...要switch干嘛”,所以如果按照官方建議,這段代碼應該是這樣的:
max_width = CONST_IMG_WIDTH - 2*off_set[0] txt_len = txtSize[0] if allign == "center": pos_x = (max_width / 2 - txt_len / 2 if max_width > txt_len else 0) + off_set[0] else if allign == "left": pos_x = off_set[0] if CONST_IMG_WIDTH - 2*off_set[0] > txt_len else 0 else if allign == "right": pos_x = max_width - txt_len if max_width > txt_len else 0 else: pos_x = ((max_width / 2 - txt_len / 2 if max_width > txt_len else 0) + off_set[0]
而我在實現上是采用了字典結構加上lamada表達式進行實現的,這里再多嘴一句,python的lamada表達式只支持單行只支持單行!因為官方覺得如果一個lamada表達式需要多行才能解決問題,那你還是去定義個函數吧!
啊?你說上面的代碼還是沒搞懂?嗯...好吧,那我把代碼好好講講。
首先,代碼是使用了一些簡寫的,我們把它拆出來:
def center(max_width, txt_len, off): return (max_width / 2 - txt_len / 2 if max_width > txt_len else 0) + off def left(max_width, txt_len, off): return off if max_width > txt_len else 0 def right(max_width, txt_len, off): return max_width - txt_len if max_width > txt_len else 0 dict_temp = { # 居中對齊 "center": center, # 左對齊 "left": left, # 右對齊 "right": right } pos_x_func = dict_temp[allign if allign in ("center", "left", "right") else "center"] pos_x = pos_x_func(CONST_IMG_WIDTH - 2*off_set[0], txtSize[0], off_set[0])
得益于python動態語言的特性,我們可以把所有的中間變量都去掉,就形成了樣例中的那種代碼結構了,這個屬于加大閱讀難度的(但代碼看上去簡潔了啊!)大家搞不懂的也無所謂,我就主要簡單介紹一下lamada表達式了。
從上面分解的代碼可以看出,lamada實際上也是函數,有入參有返回值,但就是沒了個名字,所以他實際上是一個匿名函數,其構成是這樣的:
lamada 參數1 [, 參數n] : 表達式
記住了,Python不支持多行lamada!
感覺這次文章基礎語法扯的有點多了,之后的文章對基礎語法的介紹會進一步減少的!
本次的代碼樣例同樣在我的GitHub上可以找到
好的,那么接下來
額...好吧,下次我們就來解決上面這個問題!
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/42126.html
摘要:在上一篇文章圖工具的優化實現文本居中中,我們已經實現了對插入字體的左中右對齊顯示,那因為上期文章混進去了不少語法講解,所以后面的內容就順延到這啦,哈哈哈。 showImg(https://segmentfault.com/img/bVbeIu4?w=250&h=250); 在上一篇文章【圖工具的優化——實現文本居中】中,我們已經實現了對插入字體的左中右對齊顯示,那因為上期文章混進去了不...
摘要:因此,本文將會以一些正經的嚴謹的有深度的大概吧的課題,慢慢的接觸人工智能的相關知識。 Before The Beginning ????近年,技術圈炒的最火的兩個話(ba)題(gua)不外乎就是人工智障智能以及炒幣區塊鏈了,這個系列文章我主要以一個小菜鳥的角度一步一步的對人工智能的相關知識做一點了解,也算是一個顫顫巍巍追著AI浪潮公交車的社會主義五好青年,咳咳,扯遠了...其實對于人工...
摘要:與的特點比較這兩個目前都是小眾語言做了些時間的研究寫了點東西有了點心得相似點有衛生宏區別與的不衛生宏在類或定義體之外定義函數代碼沒有分成頭與實現體例如的頭與實現的與定義的接口定義與實現定義是分開的而與是不分開的運用函數式編程高階函數目前是新 nim與rust的特點比較 這兩個目前都是小眾語言,做了些時間的研究,寫了點東西有了點心得 相似點: 有衛生宏.區別與C++的(不衛生)宏 在類...
摘要:是你學習從入門到專家必備的學習路線和優質學習資源。的數學基礎最主要是高等數學線性代數概率論與數理統計三門課程,這三門課程是本科必修的。其作為機器學習的入門和進階資料非常適合。書籍介紹深度學習通常又被稱為花書,深度學習領域最經典的暢銷書。 showImg(https://segmentfault.com/img/remote/1460000019011569); 【導讀】本文由知名開源平...
閱讀 2874·2021-08-20 09:37
閱讀 1613·2019-08-30 12:47
閱讀 1096·2019-08-29 13:27
閱讀 1691·2019-08-28 18:02
閱讀 754·2019-08-23 18:15
閱讀 3090·2019-08-23 16:51
閱讀 937·2019-08-23 14:13
閱讀 2140·2019-08-23 13:05