Python pyside6編寫一個(gè)廣告圖片生成器
一、效果圖

二、說明書
廣告圖片生成器使用說明
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",可通過"選擇路徑"按鈕更改
2. 圖片處理
選擇圖片: 點(diǎn)擊"選擇產(chǎn)品圖片"按鈕選擇要使用的圖片
去背景功能:
- 可通過復(fù)選框開啟/關(guān)閉去背景功能
- 使用滑動(dòng)條調(diào)整去背景閾值(180-250)
- 點(diǎn)擊"預(yù)覽去背景"查看效果
3. 樣式設(shè)置
背景顏色: 點(diǎn)擊"選擇背景顏色"按鈕自定義背景色
文字顏色: 點(diǎn)擊"選擇文字顏色"按鈕自定義文字顏色
4. 生成和保存
生成預(yù)覽: 所有設(shè)置完成后會自動(dòng)預(yù)覽效果
生成圖片: 點(diǎn)擊"生成廣告圖片"按鈕生成最終圖片
保存圖片: 點(diǎn)擊"保存圖片"按鈕將圖片保存到指定位置
布局說明
文字區(qū)域占圖片寬度的1/3,位于左側(cè)
產(chǎn)品圖片占圖片寬度的2/3,位于右側(cè)
文字和圖片都會自動(dòng)居中對齊
注意事項(xiàng)
去背景功能最適合處理白色或淺色背景的圖片
文字會根據(jù)區(qū)域大小自動(dòng)換行
圖片會自動(dòng)等比例縮放以適應(yīng)區(qū)域
每次生成的圖片會自動(dòng)以時(shí)間戳命名
系統(tǒng)要求
操作系統(tǒng):Windows
Python環(huán)境
需要安裝的庫:
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)對話框
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("使用說明")
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)
# 讀取說明文件
try:
with open("readme.md", "r", encoding="utf-8") as f:
help_text = f.read()
except:
help_text = "找不到說明文件"
# 創(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("使用說明")
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)
# 如果高度超出,按高度縮放,但保持寬度不超過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) # 取較小值確保不超過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)
# 如果高度超出,按高度縮放,但保持寬度不超過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) # 取較小值確保不超過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)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Python代碼實(shí)現(xiàn)PDF與Word之間互轉(zhuǎn)
這篇文章主要介紹了如何使用Python的pdf2docx和win32com庫進(jìn)行PDF與DOCX之間的轉(zhuǎn)換,包括單個(gè)文件和批量文件的處理,文中的示例代碼講解詳細(xì),有需要的小伙伴可以了解下2026-03-03
Python實(shí)現(xiàn)將MySQL數(shù)據(jù)庫表中的數(shù)據(jù)導(dǎo)出生成csv格式文件的方法
這篇文章主要介紹了Python實(shí)現(xiàn)將MySQL數(shù)據(jù)庫表中的數(shù)據(jù)導(dǎo)出生成csv格式文件的方法,涉及Python針對mysql數(shù)據(jù)庫的連接、查詢、csv格式數(shù)據(jù)文件的生成等相關(guān)操作技巧,需要的朋友可以參考下2018-01-01
python列表添加元素append(),extend(),insert(),+list的區(qū)別及說明
這篇文章主要介紹了python列表添加元素append(),extend(), insert(),+list的區(qū)別及說明,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-12-12
python數(shù)據(jù)處理和數(shù)據(jù)清洗的示例詳解
數(shù)據(jù)清洗是指發(fā)現(xiàn)并糾正數(shù)據(jù)文件中可識別的錯(cuò)誤的最后一道程序,包括檢查數(shù)據(jù)一致性,處理無效值和缺失值等,數(shù)據(jù)清洗與處理的目的是提高數(shù)據(jù)的質(zhì)量,提高實(shí)驗(yàn)結(jié)果的可靠度,本文給大家介紹了python數(shù)據(jù)處理和數(shù)據(jù)清洗的示例,需要的朋友可以參考下2024-08-08
樹莓派使用python-librtmp實(shí)現(xiàn)rtmp推流h264的方法
今天小編就為大家分享一篇樹莓派使用python-librtmp實(shí)現(xiàn)rtmp推流h264的方法,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧2019-07-07
python將dict中的unicode打印成中文實(shí)例
這篇文章主要介紹了python將dict中的unicode打印成中文實(shí)例,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-05-05

