Python pyside6編寫一個(gè)廣告圖片生成器
一、效果圖
二、說(shuō)明書
廣告圖片生成器使用說(shuō)明
1.軟件功能
這是一個(gè)用于生成廣告圖片的工具,可以快速制作包含產(chǎn)品圖片和文字的廣告圖片。
2.主要特點(diǎn)
- 自定義廣告尺寸(默認(rèn)620×420像素)
- 智能去除產(chǎn)品圖片背景
- 自動(dòng)排版(左文右圖布局)
- 自動(dòng)文字換行
- 可自定義顏色和文字
使用步驟
1. 基本設(shè)置
廣告尺寸: 可設(shè)置寬度(300-1920px)和高度(200-1080px)
廣告文本: 在文本框中輸入需要顯示的廣告文字
輸出路徑: 默認(rèn)為"D:\PIC",可通過(guò)"選擇路徑"按鈕更改
2. 圖片處理
選擇圖片: 點(diǎn)擊"選擇產(chǎn)品圖片"按鈕選擇要使用的圖片
去背景功能:
- 可通過(guò)復(fù)選框開啟/關(guān)閉去背景功能
- 使用滑動(dòng)條調(diào)整去背景閾值(180-250)
- 點(diǎn)擊"預(yù)覽去背景"查看效果
3. 樣式設(shè)置
背景顏色: 點(diǎn)擊"選擇背景顏色"按鈕自定義背景色
文字顏色: 點(diǎn)擊"選擇文字顏色"按鈕自定義文字顏色
4. 生成和保存
生成預(yù)覽: 所有設(shè)置完成后會(huì)自動(dòng)預(yù)覽效果
生成圖片: 點(diǎn)擊"生成廣告圖片"按鈕生成最終圖片
保存圖片: 點(diǎn)擊"保存圖片"按鈕將圖片保存到指定位置
布局說(shuō)明
文字區(qū)域占圖片寬度的1/3,位于左側(cè)
產(chǎn)品圖片占圖片寬度的2/3,位于右側(cè)
文字和圖片都會(huì)自動(dòng)居中對(duì)齊
注意事項(xiàng)
去背景功能最適合處理白色或淺色背景的圖片
文字會(huì)根據(jù)區(qū)域大小自動(dòng)換行
圖片會(huì)自動(dòng)等比例縮放以適應(yīng)區(qū)域
每次生成的圖片會(huì)自動(dòng)以時(shí)間戳命名
系統(tǒng)要求
操作系統(tǒng):Windows
Python環(huán)境
需要安裝的庫(kù):
PySide6
Pillow (PIL)
快捷操作
可以直接拖拽圖片到軟件窗口
使用滑動(dòng)條快速調(diào)整去背景效果
實(shí)時(shí)預(yù)覽所有修改效果
三、實(shí)現(xiàn)代碼
from PySide6.QtWidgets import (QApplication, QMainWindow, QWidget, QVBoxLayout, QHBoxLayout, QPushButton, QLabel, QLineEdit, QFileDialog, QSpinBox, QColorDialog, QTextEdit, QSlider, QDialog, QCheckBox, QScrollArea) from PySide6.QtCore import Qt from PySide6.QtGui import QPixmap, QImage from PIL import Image, ImageDraw, ImageFont import sys import os import time class PreviewDialog(QDialog): def __init__(self, parent=None): super().__init__(parent) self.setWindowTitle("去背景預(yù)覽") self.setModal(False) # 非模態(tài)對(duì)話框 layout = QVBoxLayout(self) # 預(yù)覽標(biāo)簽 self.preview_label = QLabel() self.preview_label.setFixedSize(300, 300) self.preview_label.setStyleSheet("QLabel { background-color: #808080; }") # 灰色背景 self.preview_label.setAlignment(Qt.AlignCenter) layout.addWidget(self.preview_label) # 關(guān)閉按鈕 close_btn = QPushButton("關(guān)閉預(yù)覽") close_btn.clicked.connect(self.close) layout.addWidget(close_btn) class HelpDialog(QDialog): def __init__(self, parent=None): super().__init__(parent) self.setWindowTitle("使用說(shuō)明") self.setGeometry(150, 150, 600, 400) layout = QVBoxLayout(self) # 創(chuàng)建滾動(dòng)區(qū)域 scroll = QScrollArea() scroll.setWidgetResizable(True) layout.addWidget(scroll) # 創(chuàng)建內(nèi)容容器 content = QWidget() scroll.setWidget(content) content_layout = QVBoxLayout(content) # 讀取說(shuō)明文件 try: with open("readme.md", "r", encoding="utf-8") as f: help_text = f.read() except: help_text = "找不到說(shuō)明文件" # 創(chuàng)建文本顯示 text_display = QTextEdit() text_display.setReadOnly(True) text_display.setMarkdown(help_text) content_layout.addWidget(text_display) # 關(guān)閉按鈕 close_btn = QPushButton("關(guān)閉") close_btn.clicked.connect(self.close) layout.addWidget(close_btn) class AdGenerator(QMainWindow): def __init__(self): super().__init__() # 設(shè)置默認(rèn)輸出路徑 self.output_dir = "D:\\PIC" # 確保輸出目錄存在 if not os.path.exists(self.output_dir): try: os.makedirs(self.output_dir) except Exception as e: print(f"創(chuàng)建輸出目錄失敗: {str(e)}") self.output_dir = os.getcwd() # 如果創(chuàng)建失敗,使用當(dāng)前目錄 self.initUI() self.product_image_path = None self.bg_color = (30, 30, 30) self.text_color = (255, 255, 255) self.threshold = 220 # 默認(rèn)閾值 self.preview_dialog = None self.current_image = None self.remove_bg_enabled = True # 默認(rèn)啟用去背景 self.ad_width = 620 # 默認(rèn)寬度 self.ad_height = 420 # 默認(rèn)高度 self.help_dialog = None def initUI(self): self.setWindowTitle('廣告圖片生成器') self.setGeometry(100, 100, 800, 600) # 創(chuàng)建中心部件和布局 central_widget = QWidget() self.setCentralWidget(central_widget) layout = QVBoxLayout(central_widget) # 創(chuàng)建預(yù)覽標(biāo)簽 self.preview_label = QLabel() self.preview_label.setFixedSize(620, 420) self.preview_label.setStyleSheet("QLabel { background-color: #1e1e1e; }") self.preview_label.setAlignment(Qt.AlignCenter) layout.addWidget(self.preview_label) # 創(chuàng)建控制面板 controls_layout = QHBoxLayout() # 左側(cè)控制面板 left_panel = QVBoxLayout() # 添加尺寸設(shè)置 size_layout = QHBoxLayout() size_label = QLabel("廣告尺寸:") self.width_input = QSpinBox() self.width_input.setRange(300, 1920) # 設(shè)置合理的范圍 self.width_input.setValue(620) self.width_input.setSuffix(" px") self.width_input.valueChanged.connect(self.size_changed) size_x_label = QLabel("×") self.height_input = QSpinBox() self.height_input.setRange(200, 1080) self.height_input.setValue(420) self.height_input.setSuffix(" px") self.height_input.valueChanged.connect(self.size_changed) size_layout.addWidget(size_label) size_layout.addWidget(self.width_input) size_layout.addWidget(size_x_label) size_layout.addWidget(self.height_input) left_panel.addLayout(size_layout) # 文本輸入 text_layout = QVBoxLayout() text_label = QLabel("廣告文本:") self.text_input = QTextEdit() self.text_input.setPlaceholderText("輸入廣告文本") self.text_input.setMaximumHeight(100) text_layout.addWidget(text_label) text_layout.addWidget(self.text_input) left_panel.addLayout(text_layout) # 圖片選擇按鈕 self.select_image_btn = QPushButton("選擇產(chǎn)品圖片") self.select_image_btn.clicked.connect(self.select_image) left_panel.addWidget(self.select_image_btn) # 背景顏色選擇 self.bg_color_btn = QPushButton("選擇背景顏色") self.bg_color_btn.clicked.connect(self.select_bg_color) left_panel.addWidget(self.bg_color_btn) # 文字顏色選擇 self.text_color_btn = QPushButton("選擇文字顏色") self.text_color_btn.clicked.connect(self.select_text_color) left_panel.addWidget(self.text_color_btn) # 閾值選擇 threshold_layout = QHBoxLayout() # 添加去背景開關(guān) self.remove_bg_checkbox = QCheckBox("啟用去背景") self.remove_bg_checkbox.setChecked(True) self.remove_bg_checkbox.stateChanged.connect(self.toggle_remove_bg) left_panel.addWidget(self.remove_bg_checkbox) threshold_label = QLabel("去背景閾值:") self.threshold_value_label = QLabel("220") self.threshold_slider = QSlider(Qt.Horizontal) self.threshold_slider.setMinimum(180) self.threshold_slider.setMaximum(250) self.threshold_slider.setValue(220) self.threshold_slider.valueChanged.connect(self.threshold_changed) # 添加預(yù)覽按鈕 self.preview_btn = QPushButton("預(yù)覽去背景") self.preview_btn.clicked.connect(self.show_preview) threshold_layout.addWidget(threshold_label) threshold_layout.addWidget(self.threshold_slider) threshold_layout.addWidget(self.threshold_value_label) threshold_layout.addWidget(self.preview_btn) left_panel.addLayout(threshold_layout) controls_layout.addLayout(left_panel) # 右側(cè)控制面板 right_panel = QVBoxLayout() # 添加輸出路徑設(shè)置 output_layout = QHBoxLayout() output_label = QLabel("輸出路徑:") self.output_path_label = QLabel(self.output_dir) self.output_path_label.setStyleSheet("padding: 5px; background-color: #f0f0f0; border: 1px solid #ccc;") self.output_path_btn = QPushButton("選擇路徑") self.output_path_btn.clicked.connect(self.select_output_path) output_layout.addWidget(output_label) output_layout.addWidget(self.output_path_label, stretch=1) output_layout.addWidget(self.output_path_btn) right_panel.addLayout(output_layout) # 生成按鈕 self.generate_btn = QPushButton("生成廣告圖片") self.generate_btn.clicked.connect(self.generate_ad) right_panel.addWidget(self.generate_btn) # 保存按鈕 self.save_btn = QPushButton("保存圖片") self.save_btn.clicked.connect(self.save_image) right_panel.addWidget(self.save_btn) # 添加幫助按鈕 self.help_btn = QPushButton("使用說(shuō)明") self.help_btn.clicked.connect(self.show_help) right_panel.addWidget(self.help_btn) controls_layout.addLayout(right_panel) layout.addLayout(controls_layout) def select_image(self): file_name, _ = QFileDialog.getOpenFileName( self, "選擇產(chǎn)品圖片", "", "圖片文件 (*.png *.jpg *.jpeg *.bmp)" ) if file_name: self.product_image_path = file_name self.preview_image() def select_bg_color(self): color = QColorDialog.getColor() if color.isValid(): self.bg_color = (color.red(), color.green(), color.blue()) self.preview_image() def select_text_color(self): color = QColorDialog.getColor() if color.isValid(): self.text_color = (color.red(), color.green(), color.blue()) self.preview_image() def threshold_changed(self): self.threshold = self.threshold_slider.value() self.threshold_value_label.setText(str(self.threshold)) if self.preview_dialog and self.preview_dialog.isVisible(): self.show_preview() if self.product_image_path: self.preview_image() def toggle_remove_bg(self, state): self.remove_bg_enabled = bool(state) # 更新閾值控件的啟用狀態(tài) self.threshold_slider.setEnabled(self.remove_bg_enabled) self.threshold_value_label.setEnabled(self.remove_bg_enabled) self.preview_btn.setEnabled(self.remove_bg_enabled) # 如果有圖片,立即更新預(yù)覽 if self.product_image_path: self.preview_image() def remove_background(self, image): if not self.remove_bg_enabled: return image.convert('RGBA') # 轉(zhuǎn)換圖片為RGBA模式 image = image.convert('RGBA') data = image.getdata() new_data = [] for item in data: # 如果像素接近白色,則設(shè)置為透明 if item[0] >= self.threshold and item[1] >= self.threshold and item[2] >= self.threshold: new_data.append((255, 255, 255, 0)) else: new_data.append(item) image.putdata(new_data) return image def show_preview(self): if not self.product_image_path: return if not self.preview_dialog: self.preview_dialog = PreviewDialog(self) try: # 加載原圖并去背景 img = Image.open(self.product_image_path) img = self.remove_background(img) # 調(diào)整圖片大小以適應(yīng)預(yù)覽窗口 preview_size = 300 img.thumbnail((preview_size, preview_size), Image.Resampling.LANCZOS) # 轉(zhuǎn)換為QImage img_data = img.convert("RGBA").tobytes("raw", "RGBA") qimg = QImage(img_data, img.size[0], img.size[1], QImage.Format_RGBA8888) # 顯示在預(yù)覽窗口中 pixmap = QPixmap.fromImage(qimg) self.preview_dialog.preview_label.setPixmap(pixmap) # 顯示預(yù)覽窗口 self.preview_dialog.show() except Exception as e: print(f"預(yù)覽出錯(cuò): {str(e)}") def preview_image(self): self.current_image = self.generate_ad(preview=True) if self.current_image: pixmap = QPixmap.fromImage(self.current_image) self.preview_label.setPixmap(pixmap.scaled( self.preview_label.size(), Qt.KeepAspectRatio, Qt.SmoothTransformation )) def generate_ad(self, preview=False): width, height = self.ad_width, self.ad_height # 使用設(shè)置的尺寸 image = Image.new('RGB', (width, height), self.bg_color) draw = ImageDraw.Draw(image) if self.product_image_path and os.path.exists(self.product_image_path): try: product_img = Image.open(self.product_image_path) product_img = self.remove_background(product_img) # 嚴(yán)格計(jì)算2/3寬度 right_width = int(width * (2/3)) # 確保寬度正好是2/3 product_height = int((right_width * product_img.height) / product_img.width) # 如果高度超出,按高度縮放,但保持寬度不超過(guò)2/3 if product_height > height: product_height = height calc_width = int((product_height * product_img.width) / product_img.height) right_width = min(calc_width, right_width) # 取較小值確保不超過(guò)2/3 product_img = product_img.resize((right_width, product_height)) # 計(jì)算粘貼位置(右側(cè)居中) paste_x = width - right_width paste_y = (height - product_height) // 2 # 粘貼產(chǎn)品圖片 image.paste(product_img, (paste_x, paste_y), product_img) except Exception as e: print(f"處理圖片時(shí)出錯(cuò): {str(e)}") try: # 根據(jù)廣告尺寸調(diào)整字體大小 font_size = min(32, int(height / 13)) # 動(dòng)態(tài)計(jì)算合適的字體大小 font = ImageFont.truetype("msyh.ttc", font_size) except: font = ImageFont.load_default() # 文本區(qū)域(使用左側(cè)1/3的空間) text_area_width = int(width * (1/3)) # 確保文本區(qū)域是1/3 text = self.text_input.toPlainText() # 改進(jìn)的文本換行處理 lines = [] current_line = "" # 按字符分割文本(考慮中文字符) for char in text: test_line = current_line + char text_bbox = draw.textbbox((0, 0), test_line, font=font) if text_bbox[2] - text_bbox[0] > text_area_width - 40: # 留出左右邊距 if current_line: lines.append(current_line) current_line = char else: lines.append(char) current_line = "" else: current_line += char if current_line: lines.append(current_line) # 計(jì)算文本總高度 line_height = font.size + 8 total_text_height = len(lines) * line_height # 繪制文本(左側(cè)居中) start_y = (height - total_text_height) // 2 for i, line in enumerate(lines): text_bbox = draw.textbbox((0, 0), line, font=font) text_width = text_bbox[2] - text_bbox[0] x = 30 # 增加左邊距 y = start_y + i * line_height draw.text((x, y), line, font=font, fill=self.text_color) if preview: # 轉(zhuǎn)換為QImage用于預(yù)覽 data = image.tobytes("raw", "RGB") qimage = QImage(data, image.size[0], image.size[1], QImage.Format_RGB888) return qimage else: # 生成文件名(使用時(shí)間戳) timestamp = time.strftime("%Y%m%d_%H%M%S") output_path = os.path.join(self.output_dir, f"ad_{timestamp}.png") # 創(chuàng)建圖片 width, height = self.ad_width, self.ad_height image = Image.new('RGB', (width, height), self.bg_color) draw = ImageDraw.Draw(image) if self.product_image_path and os.path.exists(self.product_image_path): try: product_img = Image.open(self.product_image_path) product_img = self.remove_background(product_img) # 嚴(yán)格計(jì)算2/3寬度 right_width = int(width * (2/3)) # 確保寬度正好是2/3 product_height = int((right_width * product_img.height) / product_img.width) # 如果高度超出,按高度縮放,但保持寬度不超過(guò)2/3 if product_height > height: product_height = height calc_width = int((product_height * product_img.width) / product_img.height) right_width = min(calc_width, right_width) # 取較小值確保不超過(guò)2/3 product_img = product_img.resize((right_width, product_height)) # 計(jì)算粘貼位置(右側(cè)居中) paste_x = width - right_width paste_y = (height - product_height) // 2 # 粘貼產(chǎn)品圖片 image.paste(product_img, (paste_x, paste_y), product_img) except Exception as e: print(f"處理圖片時(shí)出錯(cuò): {str(e)}") try: # 根據(jù)廣告尺寸調(diào)整字體大小 font_size = min(32, int(height / 13)) # 動(dòng)態(tài)計(jì)算合適的字體大小 font = ImageFont.truetype("msyh.ttc", font_size) except: font = ImageFont.load_default() # 文本區(qū)域(使用左側(cè)1/3的空間) text_area_width = int(width * (1/3)) # 確保文本區(qū)域是1/3 text = self.text_input.toPlainText() # 改進(jìn)的文本換行處理 lines = [] current_line = "" # 按字符分割文本(考慮中文字符) for char in text: test_line = current_line + char text_bbox = draw.textbbox((0, 0), test_line, font=font) if text_bbox[2] - text_bbox[0] > text_area_width - 40: # 留出左右邊距 if current_line: lines.append(current_line) current_line = char else: lines.append(char) current_line = "" else: current_line += char if current_line: lines.append(current_line) # 計(jì)算文本總高度 line_height = font.size + 8 total_text_height = len(lines) * line_height # 繪制文本(左側(cè)居中) start_y = (height - total_text_height) // 2 for i, line in enumerate(lines): text_bbox = draw.textbbox((0, 0), line, font=font) text_width = text_bbox[2] - text_bbox[0] x = 30 # 增加左邊距 y = start_y + i * line_height draw.text((x, y), line, font=font, fill=self.text_color) # 保存圖片 try: image.save(output_path) print(f"圖片已保存到: {output_path}") return output_path except Exception as e: print(f"保存圖片失敗: {str(e)}") return None def save_image(self): timestamp = time.strftime("%Y%m%d_%H%M%S") default_name = f"ad_{timestamp}.png" file_name, _ = QFileDialog.getSaveFileName( self, "保存廣告圖片", os.path.join(self.output_dir, default_name), "PNG圖片 (*.png)" ) if file_name: if self.generate_ad(): # 復(fù)制生成的圖片到選擇的位置 latest_file = os.path.join(self.output_dir, default_name) if os.path.exists(latest_file): Image.open(latest_file).save(file_name) print(f"圖片已保存到: {file_name}") else: print("找不到生成的圖片文件") def size_changed(self): # 更新尺寸 self.ad_width = self.width_input.value() self.ad_height = self.height_input.value() # 更新預(yù)覽標(biāo)簽大小 self.preview_label.setFixedSize(self.ad_width, self.ad_height) # 如果有圖片,重新生成預(yù)覽 if self.product_image_path: self.preview_image() def select_output_path(self): dir_path = QFileDialog.getExistingDirectory( self, "選擇輸出目錄", self.output_dir, QFileDialog.ShowDirsOnly ) if dir_path: self.output_dir = dir_path self.output_path_label.setText(self.output_dir) def show_help(self): if not self.help_dialog: self.help_dialog = HelpDialog(self) self.help_dialog.show() if __name__ == '__main__': app = QApplication(sys.argv) window = AdGenerator() window.show() sys.exit(app.exec())
到此這篇關(guān)于Python pyside6編寫一個(gè)廣告圖片生成器的文章就介紹到這了,更多相關(guān)Python pyside6廣告圖片生成內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Python實(shí)現(xiàn)字符串匹配的KMP算法
KMP算法的關(guān)鍵是利用匹配失敗后的信息,盡量減少模式串與主串的匹配次數(shù)以達(dá)到快速匹配的目的。這篇文章主要介紹了Python實(shí)現(xiàn)字符串匹配的KMP算法,需要的朋友可以參考下2019-04-04Python 爬取淘寶商品信息欄目的實(shí)現(xiàn)
這篇文章主要介紹了Python 爬取淘寶商品信息欄目的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2021-02-02Python實(shí)現(xiàn)批量修改文件時(shí)間屬性
我們有時(shí)候需要修改文件的“修改時(shí)間”?、?“訪問(wèn)時(shí)間”,“創(chuàng)建時(shí)間”?,此時(shí)如果使用Python批量實(shí)現(xiàn)應(yīng)該會(huì)方便很多,下面小編就來(lái)為大家介紹一下具體實(shí)現(xiàn)方法吧2023-11-11淺談python requests 的put, post 請(qǐng)求參數(shù)的問(wèn)題
今天小編就為大家分享一篇淺談python requests 的put, post 請(qǐng)求參數(shù)的問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2019-01-01Python post請(qǐng)求實(shí)現(xiàn)代碼實(shí)例
這篇文章主要介紹了Python post請(qǐng)求實(shí)現(xiàn)代碼實(shí)例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-02-02Python中Scipy庫(kù)在信號(hào)處理中的應(yīng)用詳解
信號(hào)處理作為數(shù)字信號(hào)處理領(lǐng)域的關(guān)鍵技術(shù),涵蓋了從信號(hào)獲取、傳輸、存儲(chǔ)到最終應(yīng)用的一系列處理步驟,在這篇博客中,我們將深入探討Python中Scipy庫(kù)在信號(hào)處理領(lǐng)域的應(yīng)用,需要的朋友可以參考下2023-12-12python GUI庫(kù)圖形界面開發(fā)之PyQt5中QMainWindow, QWidget以及QDialog的區(qū)別和選擇
這篇文章主要介紹了python GUI庫(kù)圖形界面開發(fā)之PyQt5中QMainWindow, QWidget以及QDialog的區(qū)別和選擇,需要的朋友可以參考下2020-02-02