利用Python自制一個(gè)批量圖片水印添加器
前段時(shí)間寫了個(gè)比較簡單的批量水印添加的python實(shí)現(xiàn)方式,將某個(gè)文件夾下面的圖片全部添加上水印。
今天正好有時(shí)間就做了一個(gè)UI應(yīng)用的封裝,這樣不需要知道python直接下載exe的應(yīng)用程序使用即可。
下面主要來介紹一下實(shí)現(xiàn)過程。
首先,還是老規(guī)矩介紹一下在開發(fā)過程中需要用到的python非標(biāo)準(zhǔn)庫,由于這些庫都是之前使用過的。
所以這里就直接導(dǎo)入到代碼塊中,如果沒有的話直接使用pip的方式進(jìn)行安裝即可。
#?It?imports?all?the?classes,?attributes,?and?methods?of?the?PyQt5.QtCore?module?into?the?global?symbol?table. from?PyQt5.QtCore?import?* #?It?imports?all?the?classes,?attributes,?and?methods?of?the?PyQt5.QtWidgets?module?into?the?global?symbol?table. from?PyQt5.QtWidgets?import?QApplication,?QWidget,?QHBoxLayout,?QVBoxLayout,?QTextBrowser,?QLineEdit,?QPushButton,?\ ????QFormLayout,?QFileDialog,?QLabel #?It?imports?all?the?classes,?attributes,?and?methods?of?the?PyQt5.QtGui?module?into?the?global?symbol?table. from?PyQt5.QtGui?import?QIcon,?QFont,?QTextCursor #?It?imports?the?sys?module. import?sys #?It?imports?the?os?module. import?os #?It?imports?the?logger?from?the?loguru?module. from?loguru?import?logger #?It?imports?the?add_mark?function?from?the?marker?module?in?the?watermarker?package. from?watermarker.marker?import?add_mark
以上導(dǎo)入的python庫就是在整個(gè)UI桌面應(yīng)用開發(fā)過程中需要用到的,完成直接我們新建UI類PicWaterUI專門用來寫一些關(guān)于桌面應(yīng)用的布局。
其中包括按鈕、輸入框等組件,此外將組件關(guān)聯(lián)的槽函數(shù)也寫入到這個(gè)類中,這樣有利于統(tǒng)一管理,代碼量比較多有需要的朋友耐心閱讀。
#?This?class?is?a?widget?that?contains?a?QLabel?and?a?QPushButton class?PicWaterUI(QWidget): ????def?__init__(self): ????????""" ????????A?constructor.?It?is?called?when?an?object?is?created?from?a?class?and?it?allows?the?class?to?initialize?the ????????attributes?of?a?class. ????????""" ????????super(PicWaterUI,?self).__init__() ????????self.init_ui() ????def?init_ui(self): ????????""" ????????This?function?initializes?the?UI. ????????""" ????????self.setWindowTitle('批量圖片水印添加器??公眾號(hào):Python 集中營!') ????????self.setWindowIcon(QIcon('water.ico')) ????????self.brower?=?QTextBrowser() ????????self.brower.setFont(QFont('宋體',?8)) ????????self.brower.setReadOnly(True) ????????self.brower.setPlaceholderText('處理進(jìn)程展示區(qū)域...') ????????self.brower.ensureCursorVisible() ????????self.pic_file_path?=?QLineEdit() ????????self.pic_file_path.setPlaceholderText('源批量圖片路徑') ????????self.pic_file_path.setReadOnly(True) ????????self.pic_file_path_btn?=?QPushButton() ????????self.pic_file_path_btn.setText('源圖片路徑') ????????self.pic_file_path_btn.clicked.connect(self.pic_file_path_btn_click) ????????self.new_pic_file_path?=?QLineEdit() ????????self.new_pic_file_path.setPlaceholderText('新圖片存儲(chǔ)路徑') ????????self.new_pic_file_path.setReadOnly(True) ????????self.new_pic_file_path_btn?=?QPushButton() ????????self.new_pic_file_path_btn.setText('保存路徑') ????????self.new_pic_file_path_btn.clicked.connect(self.new_pic_file_path_btn_click) ????????self.water_current_label?=?QLabel() ????????self.water_current_label.setText('水印內(nèi)容:') ????????self.water_current_in?=?QLineEdit() ????????self.water_current_in.setPlaceholderText('Python?集中營') ????????self.water_angle_label?=?QLabel() ????????self.water_angle_label.setText('水印角度:') ????????self.water_angle_in?=?QLineEdit() ????????self.water_angle_in.setPlaceholderText('30') ????????self.water_back_label?=?QLabel() ????????self.water_back_label.setText('水印透明度:') ????????self.water_back_in?=?QLineEdit() ????????self.water_back_in.setPlaceholderText('0.3') ????????self.water_font_label?=?QLabel() ????????self.water_font_label.setText('水印字體大?。?) ????????self.water_font_in?=?QLineEdit() ????????self.water_font_in.setPlaceholderText('30') ????????self.water_space_label?=?QLabel() ????????self.water_space_label.setText('水印間隔:') ????????self.water_space_in?=?QLineEdit() ????????self.water_space_in.setPlaceholderText('40') ????????self.water_color_label?=?QLabel() ????????self.water_color_label.setText('水印顏色:') ????????self.water_color_in?=?QLineEdit() ????????self.water_color_in.setPlaceholderText('#8B8B1B') ????????self.start_btn?=?QPushButton() ????????self.start_btn.setText('開始添加水印') ????????self.start_btn.clicked.connect(self.start_btn_click) ????????hbox?=?QHBoxLayout() ????????hbox.addWidget(self.brower) ????????fbox?=?QFormLayout() ????????fbox.addRow(self.pic_file_path,?self.pic_file_path_btn) ????????fbox.addRow(self.new_pic_file_path,?self.new_pic_file_path_btn) ????????fbox.addRow(self.water_current_label,?self.water_current_in) ????????fbox.addRow(self.water_angle_label,?self.water_angle_in) ????????fbox.addRow(self.water_back_label,?self.water_back_in) ????????fbox.addRow(self.water_font_label,?self.water_font_in) ????????fbox.addRow(self.water_space_label,?self.water_space_in) ????????fbox.addRow(self.water_color_label,?self.water_color_in) ????????v_vbox?=?QVBoxLayout() ????????v_vbox.addWidget(self.start_btn) ????????vbox?=?QVBoxLayout() ????????vbox.addLayout(fbox) ????????vbox.addLayout(v_vbox) ????????hbox.addLayout(vbox) ????????self.thread_?=?PicWaterThread(self) ????????self.thread_.message.connect(self.show_message) ????????self.thread_.finished.connect(self.finshed) ????????self.setLayout(hbox) ????def?show_message(self,?text): ????????""" ????????It?shows?a?message ????????:param?text:?The?text?to?be?displayed ????????""" ????????cursor?=?self.brower.textCursor() ????????cursor.movePosition(QTextCursor.End) ????????self.brower.append(text) ????????self.brower.setTextCursor(cursor) ????????self.brower.ensureCursorVisible() ????def?pic_file_path_btn_click(self): ????????""" ????????It?opens?a?file?dialog?box?and?allows?the?user?to?select?a?file. ????????""" ????????pic_file_path?=?QFileDialog.getExistingDirectory(self,?'選擇文件夾',?os.getcwd()) ????????self.pic_file_path.setText(pic_file_path) ????def?new_pic_file_path_btn_click(self): ????????""" ????????This?function?opens?a?file?dialog?box?and?allows?the?user?to?select?a?file?to?save?the?output?to. ????????""" ????????new_pic_file_path?=?QFileDialog.getExistingDirectory(self,?'選擇文件夾',?os.getcwd()) ????????self.new_pic_file_path.setText(new_pic_file_path) ????def?start_btn_click(self): ????????""" ????????A?function?that?is?called?when?the?start?button?is?clicked. ????????""" ????????self.thread_.start() ????????self.start_btn.setEnabled(False) ????def?finshed(self,?finished): ????????""" ????????:param?finished:?A?boolean?value?that?is?True?if?the?download?is?finished,?False?otherwise ????????""" ????????if?finished?is?True: ????????????self.start_btn.setEnabled(True)
頁面布局及組件部分完成之后就是業(yè)務(wù)的具體實(shí)現(xiàn)部分了,業(yè)務(wù)就是實(shí)現(xiàn)批量添加水印的效果。
這里新建了一個(gè)PicWaterThread類作為UI桌面應(yīng)用的子線程專門將業(yè)務(wù)實(shí)現(xiàn)的部分寫到這個(gè)類中。
業(yè)務(wù)部分和主線程直接分離時(shí),一來從代碼層面上看起來比較明了,二來在子線程執(zhí)行業(yè)務(wù)比較慢的情況下不至于導(dǎo)致主線程出現(xiàn)卡死的情況發(fā)生。
為了達(dá)到業(yè)務(wù)和界面分離的效果,下面PicWaterThread子線程的run函數(shù)里面就是具體的業(yè)務(wù)實(shí)現(xiàn)部分。
#?This?class?is?a?subclass?of?QThread,?and?it's?used?to?watermark?pictures class?PicWaterThread(QThread): ????#?A?signal?that?is?emitted?when?a?message?is?received. ????message?=?pyqtSignal(str) ????#?A?signal?that?is?emitted?when?the?download?is?finished. ????finished?=?pyqtSignal(bool) ????def?__init__(self,?parent=None): ????????""" ????????A?constructor?that?initializes?the?class. ????????:param?parent:?The?parent?widget ????????""" ????????super(PicWaterThread,?self).__init__(parent) ????????self.working?=?True ????????self.parent?=?parent ????def?__del__(self): ????????""" ????????A?destructor.?It?is?called?when?the?object?is?destroyed. ????????""" ????????self.working?=?True ????????self.wait() ????def?run(self)?->?None: ????????""" ????????>?This?function?runs?the?program ????????""" ????????try: ????????????directory?=?self.parent.pic_file_path.text().strip() ????????????water_name?=?self.parent.water_current_in.text().strip() ????????????new_directory?=?self.parent.new_pic_file_path.text().strip() ????????????water_angle_in?=?self.parent.water_angle_in.text().strip() ????????????water_back_in?=?self.parent.water_back_in.text().strip() ????????????water_font_in?=?self.parent.water_font_in.text().strip() ????????????water_space_in?=?self.parent.water_space_in.text().strip() ????????????color?=?self.parent.water_color_in.text().strip() ????????????self.message.emit('源文件路徑:{}'.format(directory)) ????????????self.message.emit('水印內(nèi)容:{}'.format(water_name)) ????????????self.message.emit('保存文件路徑:{}'.format(new_directory)) ????????????self.message.emit('水印角度:{}'.format(water_angle_in)) ????????????self.message.emit('水印透明度:{}'.format(water_back_in)) ????????????self.message.emit('水印字體大?。簕}'.format(water_font_in)) ????????????self.message.emit('水印間隔:{}'.format(water_space_in)) ????????????self.message.emit('水印顏色:{}'.format(color)) ????????????if?directory?is?None?or?water_name?is?None: ????????????????logger.info('文件夾地址或水印名稱不能為空!') ????????????????return ????????????for?file_name?in?os.listdir(directory): ????????????????logger.info('當(dāng)前文件名稱:{0},即將開始添加水印操作!'.format(file_name)) ????????????????self.message.emit('當(dāng)前文件名稱:{0},即將開始添加水印操作!'.format(file_name)) ????????????????add_mark(file=os.path.join(directory,?file_name),?out=new_directory,?mark=water_name, ?????????????????????????opacity=float(water_back_in),?angle=int(water_angle_in),?space=int(water_space_in), ?????????????????????????size=int(water_font_in),?color=color) ????????????????self.message.emit('當(dāng)前文件名稱:{0},已經(jīng)完成添加水印操作!'.format(file_name)) ????????????????logger.info('當(dāng)前文件名稱:{0},已經(jīng)完成添加水印操作!'.format(file_name)) ????????????self.finished.emit(True) ????????except?Exception?as?e: ????????????self.message.emit('文件內(nèi)容讀取或格式化發(fā)生異常!') ????????????self.finished.emit(True)
完成業(yè)務(wù)以及頁面應(yīng)用的開發(fā)之后,我們使用main函數(shù)將整個(gè)桌面應(yīng)用調(diào)起來,這種范式基本上每個(gè)桌面應(yīng)用的使用是一樣的。
如果需要好看一些的話還可以加上我們之前提到過的各種樣式主題的應(yīng)用,在公眾號(hào)主頁上進(jìn)行搜索就可以找到之前發(fā)表的相關(guān)的文章。
if?__name__?==?'__main__': ????app?=?QApplication(sys.argv) ????main?=?PicWaterUI() ????main.show() ????sys.exit(app.exec_())
最后,我們找了兩張斗羅大陸'唐三'的照片測試一下效果如何,使用上面的main函數(shù)啟動(dòng)整個(gè)應(yīng)用之后是怎樣的。
大家可以直接在應(yīng)用上面選擇需要批量添加水印的圖片路徑以及添加完成后需要保存的地方。
并且可以在生成時(shí)在桌面應(yīng)用上調(diào)整水印相關(guān)的各種參數(shù),包括水印的大小、尺寸、間隔、顏色等等,這樣就可以根據(jù)自己的需要對(duì)批量圖片制作屬于的水印效果了。
到此這篇關(guān)于利用Python自制一個(gè)批量圖片水印添加器的文章就介紹到這了,更多相關(guān)Python圖片水印添加內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
詳解python中靜態(tài)方法staticmethod用法
本文主要介紹了python中靜態(tài)方法staticmethod用法,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2022-07-07Python游戲開發(fā)之Pygame使用的最全教程分享
Pygame庫是Python中一個(gè)專為游戲開發(fā)設(shè)計(jì)的庫,它提供了大量的功能來幫助開發(fā)者創(chuàng)建各種2D游戲,本文就來和大家分享一下Pygame的具體使用,希望對(duì)大家有所幫助2023-05-05python3利用venv配置虛擬環(huán)境及過程中的小問題小結(jié)
這篇文章主要介紹了python3利用venv配置虛擬環(huán)境及過程中的小問題小結(jié),小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2018-08-08Pycharm運(yùn)行加載文本出現(xiàn)錯(cuò)誤的解決方法
今天小編就為大家分享一篇Pycharm運(yùn)行加載文本出現(xiàn)錯(cuò)誤的解決方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2019-06-06python中pip無法正確安裝或路徑出錯(cuò)的解決方案
這篇文章主要介紹了python中pip無法正確安裝或路徑出錯(cuò)的解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-02-02Tensorflow使用Anaconda、pycharm安裝記錄
這篇文章主要介紹了Tensorflow使用Anaconda、pycharm安裝記錄,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-07-07