使用Python開(kāi)發(fā)一個(gè)桌面版PDF蓋章工具
一、項(xiàng)目概述
這個(gè)工具的主要功能包括:
- 打開(kāi)和預(yù)覽PDF文件
- 加載印章圖片(支持PNG、JPG等格式)
- 在PDF頁(yè)面上精確點(diǎn)擊添加印章
- 調(diào)整印章大小
- 撤銷(xiāo)操作、清空頁(yè)面印章
- 保存蓋章后的PDF文件
二、環(huán)境準(zhǔn)備
首先需要安裝必要的Python庫(kù):
pip install PyQt5 PyMuPDF pillow
注意:PyMuPDF是fitz模塊的庫(kù),通過(guò)pip install PyMuPDF安裝。
三、核心代碼解析
1. PDF預(yù)覽編輯畫(huà)布類(lèi)
class PdfEditPreview(QLabel):
# 信號(hào):點(diǎn)擊坐標(biāo) (x, y)
clicked_pos = pyqtSignal(float, float)
def __init__(self):
super().__init__()
self.setAlignment(Qt.AlignCenter)
self.setStyleSheet('background: #e0e0e0; color: #888;')
self.setText("請(qǐng)打開(kāi) PDF 文件")
self.doc = None # PDF文檔對(duì)象
self.page_index = 0 # 當(dāng)前頁(yè)碼
self.current_pixmap = None # 當(dāng)前頁(yè)面圖像
self.stamps_to_draw = [] # 當(dāng)前頁(yè)印章列表這個(gè)類(lèi)繼承自QLabel,負(fù)責(zé)顯示PDF頁(yè)面并處理用戶(hù)點(diǎn)擊。關(guān)鍵點(diǎn):
- 坐標(biāo)轉(zhuǎn)換:將屏幕點(diǎn)擊坐標(biāo)轉(zhuǎn)換為PDF點(diǎn)坐標(biāo)(1點(diǎn)=1/72英寸)
- 自適應(yīng)高度:根據(jù)PDF頁(yè)面比例自動(dòng)調(diào)整顯示高度
- 印章疊加:在PDF頁(yè)面上繪制已添加的印章
2. 印章添加邏輯
def add_stamp(self, pdf_x, pdf_y):
if not self.doc or self.seal_bytes is None:
QMessageBox.warning(self, "提示", "請(qǐng)先加載 PDF 和 印章圖片!")
return
scale = self.spin_scale.value() / 100.0
# 計(jì)算印章在PDF中的實(shí)際尺寸
actual_w = self.seal_w_pt * scale
actual_h = actual_w * self.seal_ratio
stamp_record = {
'page': self.current_page,
'x': pdf_x, # PDF坐標(biāo)X
'y': pdf_y, # PDF坐標(biāo)Y
'w_pt': actual_w, # 印章寬度(點(diǎn))
'h_pt': actual_h, # 印章高度(點(diǎn))
'img_bytes': self.seal_bytes, # 印章圖片原始數(shù)據(jù)
'pixmap': self.seal_pixmap # 用于顯示的QPixmap
}
self.stamps_list.append(stamp_record)
self.refresh_preview()3. 滾動(dòng)預(yù)覽的修復(fù)
原版本存在預(yù)覽區(qū)域底部被裁剪的問(wèn)題,修復(fù)方案:
# 創(chuàng)建滾動(dòng)區(qū)域
self.scroll_area = QScrollArea()
self.scroll_area.setWidget(self.preview)
self.scroll_area.setWidgetResizable(True) # 關(guān)鍵:讓預(yù)覽組件寬度跟隨滾動(dòng)區(qū)
self.scroll_area.setStyleSheet("border: 2px dashed #aaa;")
# 在預(yù)覽類(lèi)中實(shí)現(xiàn)自適應(yīng)高度
def adjust_height(self):
"""根據(jù)當(dāng)前控件寬度和圖片比例,自動(dòng)調(diào)整控件高度"""
if not self.current_pixmap or self.img_w_raw == 0:
return
# 計(jì)算寬高比
ratio = self.img_h_raw / self.img_w_raw
# 目標(biāo)高度 = 當(dāng)前寬度 * 比例
target_height = int(self.width() * ratio)
# 設(shè)置最小高度,這樣ScrollArea就會(huì)出現(xiàn)滾動(dòng)條
if self.minimumHeight() != target_height:
self.setMinimumHeight(target_height)4. 保存PDF文件
def save_pdf(self):
if not self.doc: return
if not self.stamps_list:
QMessageBox.information(self, "提示", "當(dāng)前沒(méi)有蓋任何章,不需要保存。")
return
save_path, _ = QFileDialog.getSaveFileName(
self, "保存文件",
self.pdf_path.replace(".pdf", "_stamped.pdf"),
"PDF Files (*.pdf)"
)
for stamp in self.stamps_list:
page = self.doc[stamp['page']]
# 計(jì)算印章在PDF中的位置
rect_x0 = stamp['x'] - stamp['w_pt'] / 2
rect_y0 = stamp['y'] - stamp['h_pt'] / 2
rect_x1 = stamp['x'] + stamp['w_pt'] / 2
rect_y1 = stamp['y'] + stamp['h_pt'] / 2
rect = fitz.Rect(rect_x0, rect_y0, rect_x1, rect_y1)
# 將印章插入PDF
page.insert_image(rect, stream=stamp['img_bytes'])四、界面布局設(shè)計(jì)
工具界面分為三個(gè)主要區(qū)域:
+----------------+-------------------------------+ | 左側(cè)工具欄 | PDF預(yù)覽區(qū) | | | (帶滾動(dòng)條,支持長(zhǎng)頁(yè)面) | +----------------+-------------------------------+ | | 頁(yè)面導(dǎo)航條 | +----------------+-------------------------------+
左側(cè)工具欄包含:
- 文件操作區(qū)域:打開(kāi)PDF文件
- 印章設(shè)置區(qū)域:選擇印章圖片、調(diào)整大小
- 編輯控制區(qū)域:撤銷(xiāo)、清空操作
- 保存按鈕
五、使用步驟
- 打開(kāi)PDF文件:點(diǎn)擊"打開(kāi)PDF"按鈕選擇文件
- 加載印章:點(diǎn)擊"選擇印章"按鈕,支持PNG、JPG等格式
- 調(diào)整印章大小:通過(guò)縮放比例旋鈕調(diào)整(5%-500%)
- 添加印章:在PDF預(yù)覽區(qū)域點(diǎn)擊鼠標(biāo)左鍵
- 編輯操作:可撤銷(xiāo)最后一個(gè)印章或清空當(dāng)前頁(yè)
- 保存文件:點(diǎn)擊"另存為PDF"保存蓋章后的文件
六、技術(shù)要點(diǎn)
- 坐標(biāo)系統(tǒng)轉(zhuǎn)換:需要在屏幕像素坐標(biāo)、PDF點(diǎn)坐標(biāo)和圖像顯示坐標(biāo)之間進(jìn)行精確轉(zhuǎn)換
- 圖像處理:使用Pillow處理印章圖片的透明通道
- 內(nèi)存管理:及時(shí)關(guān)閉PDF文檔,避免內(nèi)存泄漏
- 用戶(hù)體驗(yàn):添加撤銷(xiāo)功能、實(shí)時(shí)預(yù)覽和錯(cuò)誤提示
七、完整代碼
以下是完整的Python代碼:
import sys
import os
import fitz # PyMuPDF
from io import BytesIO
from PIL import Image
from PyQt5.QtWidgets import (
QApplication, QMainWindow, QWidget, QVBoxLayout, QHBoxLayout,
QGridLayout, QPushButton, QLabel, QFileDialog, QMessageBox,
QSpinBox, QGroupBox, QLineEdit, QSplitter, QScrollArea
)
from PyQt5.QtCore import Qt, pyqtSignal, QRect
from PyQt5.QtGui import QPixmap, QImage, QPainter, QPen, QColor, QIcon
# ===========================
# PDF 預(yù)覽/編輯畫(huà)布
# ===========================
class PdfEditPreview(QLabel):
# 信號(hào):點(diǎn)擊坐標(biāo) (x, y)
clicked_pos = pyqtSignal(float, float)
def __init__(self):
super().__init__()
self.setAlignment(Qt.AlignCenter)
# 去掉固定的 border 樣式,改由 ScrollArea 管理外觀,這里只保留背景
self.setStyleSheet('background: #e0e0e0; color: #888;')
self.setText("請(qǐng)打開(kāi) PDF 文件")
self.doc = None
self.page_index = 0
self.current_pixmap = None
# 存儲(chǔ)當(dāng)前頁(yè)面的已蓋章列表 (由主窗口傳入)
self.stamps_to_draw = []
# 坐標(biāo)轉(zhuǎn)換參數(shù)
self.img_w_raw = 0.0
self.img_h_raw = 0.0
def load_page(self, doc, index):
self.doc = doc
self.page_index = index
self.render()
def render(self):
if not self.doc: return
page = self.doc[self.page_index]
# 獲取 120 DPI 的圖像用于顯示
pix = page.get_pixmap(dpi=120)
self.img_w_raw = pix.width
self.img_h_raw = pix.height
img = QImage(pix.samples, self.img_w_raw, self.img_h_raw, pix.stride, QImage.Format_RGB888)
self.current_pixmap = QPixmap.fromImage(img)
# 加載新圖片后,立即調(diào)整控件高度以適應(yīng)比例
self.adjust_height()
self.update()
def adjust_height(self):
"""根據(jù)當(dāng)前控件寬度和圖片比例,自動(dòng)調(diào)整控件高度,確保底部不被裁剪"""
if not self.current_pixmap or self.img_w_raw == 0:
return
# 計(jì)算寬高比
ratio = self.img_h_raw / self.img_w_raw
# 目標(biāo)高度 = 當(dāng)前寬度 * 比例
target_height = int(self.width() * ratio)
# 設(shè)置最小高度,這樣 ScrollArea 就會(huì)出現(xiàn)滾動(dòng)條
if self.minimumHeight() != target_height:
self.setMinimumHeight(target_height)
def resizeEvent(self, event):
"""當(dāng)窗口大小改變(寬度改變)時(shí),重新計(jì)算高度"""
super().resizeEvent(event)
self.adjust_height()
def set_stamps(self, stamps_list):
"""接收主窗口傳來(lái)的當(dāng)前頁(yè)蓋章數(shù)據(jù),用于重繪"""
self.stamps_to_draw = stamps_list
self.update()
def mousePressEvent(self, e):
if not self.doc or not self.current_pixmap: return
# 計(jì)算圖片在 Label 中的顯示區(qū)域(居中)
scaled_pix = self.current_pixmap.scaledToWidth(self.width(), Qt.SmoothTransformation)
img_x_start = (self.width() - scaled_pix.width()) / 2
img_y_start = (self.height() - scaled_pix.height()) / 2
# 獲取相對(duì)于圖片的點(diǎn)擊坐標(biāo)
click_x = e.x() - img_x_start
click_y = e.y() - img_y_start
# 檢查是否點(diǎn)擊在圖片范圍內(nèi)
if click_x < 0 or click_x > scaled_pix.width() or \
click_y < 0 or click_y > scaled_pix.height():
return
# 轉(zhuǎn)換為 PDF 點(diǎn)坐標(biāo) (PDF Points)
pdf_page = self.doc[self.page_index]
scale = pdf_page.rect.width / scaled_pix.width()
pdf_x = click_x * scale
pdf_y = click_y * scale
self.clicked_pos.emit(pdf_x, pdf_y)
def paintEvent(self, e):
super().paintEvent(e) # 繪制背景
if not self.doc or not self.current_pixmap: return
painter = QPainter(self)
painter.setRenderHint(QPainter.SmoothPixmapTransform)
# 1. 繪制 PDF 底圖
# 使用 scaledToWidth 確保寬度填滿(mǎn),高度隨 resizeEvent 自動(dòng)調(diào)整
scaled_pix = self.current_pixmap.scaledToWidth(self.width(), Qt.SmoothTransformation)
img_x_start = (self.width() - scaled_pix.width()) / 2
img_y_start = (self.height() - scaled_pix.height()) / 2
painter.drawPixmap(int(img_x_start), int(img_y_start), scaled_pix)
# 2. 繪制已確認(rèn)的印章 (Overlay)
pdf_page = self.doc[self.page_index]
pt_to_px = scaled_pix.width() / pdf_page.rect.width
for stamp in self.stamps_to_draw:
# 尺寸轉(zhuǎn)屏幕像素
w_screen = stamp['w_pt'] * pt_to_px
h_screen = stamp['h_pt'] * pt_to_px
# 中心坐標(biāo)轉(zhuǎn)屏幕像素
cx_screen = stamp['x'] * pt_to_px
cy_screen = stamp['y'] * pt_to_px
# 計(jì)算繪制左上角
draw_x = img_x_start + cx_screen - (w_screen / 2)
draw_y = img_y_start + cy_screen - (h_screen / 2)
target_rect = QRect(int(draw_x), int(draw_y), int(w_screen), int(h_screen))
painter.drawPixmap(target_rect, stamp['pixmap'])
# 繪制一個(gè)小紅框表示這是后加的章
painter.setPen(QPen(QColor(255, 0, 0, 100), 1, Qt.DashLine))
painter.drawRect(target_rect)
painter.end()
# ===========================
# 主窗口
# ===========================
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
# --- 數(shù)據(jù)狀態(tài) ---
self.doc = None
self.pdf_path = ""
self.current_page = 0
self.stamps_list = []
self.seal_pixmap = None
self.seal_bytes = None
self.seal_w_pt = 0.0
self.seal_ratio = 1.0
self.init_ui()
def init_ui(self):
self.setWindowTitle('PDF 手動(dòng)蓋章編輯器 (滾動(dòng)預(yù)覽修復(fù)版)')
self.setGeometry(100, 100, 1300, 850)
main_widget = QWidget()
self.setCentralWidget(main_widget)
main_layout = QHBoxLayout(main_widget)
# ===== 左側(cè):工具欄 (保持不變) =====
tools_panel = QVBoxLayout()
tools_panel.setContentsMargins(0, 0, 10, 0)
gb_file = QGroupBox("1. 文件操作")
v_file = QVBoxLayout(gb_file)
btn_open = QPushButton("?? 打開(kāi) PDF")
btn_open.setStyleSheet("padding: 8px; font-weight: bold;")
btn_open.clicked.connect(self.open_pdf)
self.lbl_info = QLabel("未加載文件")
self.lbl_info.setStyleSheet("color: #666; font-size: 11px;")
v_file.addWidget(btn_open)
v_file.addWidget(self.lbl_info)
gb_seal = QGroupBox("2. 印章設(shè)置")
v_seal = QVBoxLayout(gb_seal)
self.txt_seal_path = QLineEdit()
self.txt_seal_path.setPlaceholderText("選擇印章圖片...")
self.txt_seal_path.setReadOnly(True)
btn_sel_seal = QPushButton("??? 選擇印章")
btn_sel_seal.clicked.connect(self.select_seal)
self.spin_scale = QSpinBox()
self.spin_scale.setRange(5, 500)
self.spin_scale.setValue(35)
self.spin_scale.setSuffix(" %")
self.spin_scale.valueChanged.connect(self.update_seal_preview_info)
self.lbl_seal_preview = QLabel("印章預(yù)覽")
self.lbl_seal_preview.setAlignment(Qt.AlignCenter)
self.lbl_seal_preview.setFixedSize(150, 150)
self.lbl_seal_preview.setStyleSheet("border: 1px solid #ddd; background: #fff;")
v_seal.addWidget(btn_sel_seal)
v_seal.addWidget(self.txt_seal_path)
v_seal.addWidget(QLabel("縮放比例:"))
v_seal.addWidget(self.spin_scale)
v_seal.addWidget(self.lbl_seal_preview, 0, Qt.AlignCenter)
gb_action = QGroupBox("3. 編輯控制")
v_action = QVBoxLayout(gb_action)
btn_undo = QPushButton("?? 撤銷(xiāo)上一個(gè)印章")
btn_undo.clicked.connect(self.undo_last_stamp)
btn_clear_page = QPushButton("??? 清空當(dāng)前頁(yè)印章")
btn_clear_page.clicked.connect(self.clear_page_stamps)
v_action.addWidget(btn_undo)
v_action.addWidget(btn_clear_page)
btn_save = QPushButton("?? 另存為 PDF")
btn_save.setFixedHeight(50)
btn_save.setStyleSheet("background-color: #28a745; color: white; font-size: 14px; font-weight: bold;")
btn_save.clicked.connect(self.save_pdf)
tools_panel.addWidget(gb_file)
tools_panel.addWidget(gb_seal)
tools_panel.addWidget(gb_action)
tools_panel.addStretch()
tools_panel.addWidget(btn_save)
# ===== 中間:預(yù)覽區(qū) (修復(fù)重點(diǎn)) =====
preview_layout = QVBoxLayout()
self.preview = PdfEditPreview()
self.preview.clicked_pos.connect(self.add_stamp)
# --- 創(chuàng)建滾動(dòng)區(qū)域 ---
self.scroll_area = QScrollArea()
self.scroll_area.setWidget(self.preview)
self.scroll_area.setWidgetResizable(True) # 關(guān)鍵:讓預(yù)覽組件寬度跟隨滾動(dòng)區(qū),但高度由組件自己決定
self.scroll_area.setStyleSheet("border: 2px dashed #aaa;")
# 翻頁(yè)條
nav_layout = QHBoxLayout()
self.btn_prev = QPushButton("? 上一頁(yè)")
self.btn_next = QPushButton("下一頁(yè) ?")
self.lbl_page = QLabel("0 / 0")
self.btn_prev.clicked.connect(self.prev_page)
self.btn_next.clicked.connect(self.next_page)
nav_layout.addWidget(self.btn_prev)
nav_layout.addWidget(self.lbl_page)
nav_layout.addWidget(self.btn_next)
preview_layout.addWidget(QLabel("<b>??? 操作說(shuō)明:</b>加載 PDF 和印章后,直接在右側(cè)頁(yè)面上<b>點(diǎn)擊鼠標(biāo)左鍵</b>即可蓋章。"))
preview_layout.addWidget(self.scroll_area, 1) # 添加滾動(dòng)區(qū)域而不是直接添加 preview
preview_layout.addLayout(nav_layout)
# 組合布局
tools_widget = QWidget()
tools_widget.setLayout(tools_panel)
tools_widget.setFixedWidth(280)
main_layout.addWidget(tools_widget)
main_layout.addLayout(preview_layout)
self.update_ui_state()
# ---------- 邏輯功能 (保持不變) ----------
def open_pdf(self):
path, _ = QFileDialog.getOpenFileName(self, "打開(kāi) PDF", "", "PDF Files (*.pdf)")
if not path: return
try:
if self.doc: self.doc.close()
self.doc = fitz.open(path)
self.pdf_path = path
self.current_page = 0
self.stamps_list = []
self.lbl_info.setText(os.path.basename(path))
self.refresh_preview()
self.update_ui_state()
except Exception as e:
QMessageBox.critical(self, "錯(cuò)誤", f"無(wú)法打開(kāi)文件:\n{str(e)}")
def select_seal(self):
path, _ = QFileDialog.getOpenFileName(self, "選擇印章圖片", "", "Images (*.png *.jpg *.jpeg *.bmp)")
if not path: return
self.txt_seal_path.setText(path)
try:
pil_img = Image.open(path)
if pil_img.mode != 'RGBA':
pil_img = pil_img.convert('RGBA')
byte_io = BytesIO()
pil_img.save(byte_io, format='PNG')
self.seal_bytes = byte_io.getvalue()
img_doc = fitz.open("png", self.seal_bytes)
page = img_doc.load_page(0)
self.seal_w_pt = page.rect.width
self.seal_ratio = page.rect.height / page.rect.width
img_doc.close()
self.seal_pixmap = QPixmap(path)
self.lbl_seal_preview.setPixmap(self.seal_pixmap.scaled(
self.lbl_seal_preview.size(), Qt.KeepAspectRatio, Qt.SmoothTransformation
))
self.update_seal_preview_info()
except Exception as e:
QMessageBox.critical(self, "圖片錯(cuò)誤", f"處理印章圖片失敗:\n{e}")
def update_seal_preview_info(self):
pass
def add_stamp(self, pdf_x, pdf_y):
if not self.doc or self.seal_bytes is None:
QMessageBox.warning(self, "提示", "請(qǐng)先加載 PDF 和 印章圖片!")
return
scale = self.spin_scale.value() / 100.0
actual_w = self.seal_w_pt * scale
actual_h = actual_w * self.seal_ratio
stamp_record = {
'page': self.current_page,
'x': pdf_x,
'y': pdf_y,
'w_pt': actual_w,
'h_pt': actual_h,
'img_bytes': self.seal_bytes,
'pixmap': self.seal_pixmap
}
self.stamps_list.append(stamp_record)
self.refresh_preview()
def undo_last_stamp(self):
if not self.stamps_list: return
removed = self.stamps_list.pop()
if removed['page'] == self.current_page:
self.refresh_preview()
else:
QMessageBox.information(self, "撤銷(xiāo)", f"已撤銷(xiāo)第 {removed['page']+1} 頁(yè)上的印章")
def clear_page_stamps(self):
old_len = len(self.stamps_list)
self.stamps_list = [s for s in self.stamps_list if s['page'] != self.current_page]
if len(self.stamps_list) < old_len:
self.refresh_preview()
def refresh_preview(self):
if not self.doc: return
current_page_stamps = [s for s in self.stamps_list if s['page'] == self.current_page]
self.preview.set_stamps(current_page_stamps)
self.preview.load_page(self.doc, self.current_page)
self.lbl_page.setText(f"{self.current_page + 1} / {len(self.doc)}")
self.update_ui_state()
def prev_page(self):
if self.current_page > 0:
self.current_page -= 1
self.refresh_preview()
# 翻頁(yè)時(shí)重置滾動(dòng)條到頂部
self.scroll_area.verticalScrollBar().setValue(0)
def next_page(self):
if self.doc and self.current_page < len(self.doc) - 1:
self.current_page += 1
self.refresh_preview()
# 翻頁(yè)時(shí)重置滾動(dòng)條到頂部
self.scroll_area.verticalScrollBar().setValue(0)
def update_ui_state(self):
has_doc = self.doc is not None
self.btn_prev.setEnabled(has_doc and self.current_page > 0)
self.btn_next.setEnabled(has_doc and self.current_page < len(self.doc) - 1)
def save_pdf(self):
if not self.doc: return
if not self.stamps_list:
QMessageBox.information(self, "提示", "當(dāng)前沒(méi)有蓋任何章,不需要保存。")
return
save_path, _ = QFileDialog.getSaveFileName(self, "保存文件", self.pdf_path.replace(".pdf", "_stamped.pdf"), "PDF Files (*.pdf)")
if not save_path: return
try:
for stamp in self.stamps_list:
page = self.doc[stamp['page']]
rect_x0 = stamp['x'] - stamp['w_pt'] / 2
rect_y0 = stamp['y'] - stamp['h_pt'] / 2
rect_x1 = stamp['x'] + stamp['w_pt'] / 2
rect_y1 = stamp['y'] + stamp['h_pt'] / 2
rect = fitz.Rect(rect_x0, rect_y0, rect_x1, rect_y1)
page.insert_image(rect, stream=stamp['img_bytes'])
self.doc.save(save_path)
QMessageBox.information(self, "成功", f"文件已保存至:\n{save_path}")
self.doc.close()
self.doc = fitz.open(save_path)
self.pdf_path = save_path
self.stamps_list = []
self.refresh_preview()
except Exception as e:
QMessageBox.critical(self, "保存失敗", str(e))
if __name__ == '__main__':
QApplication.setAttribute(Qt.AA_EnableHighDpiScaling)
QApplication.setAttribute(Qt.AA_UseHighDpiPixmaps)
app = QApplication(sys.argv)
w = MainWindow()
w.show()
sys.exit(app.exec_())八、擴(kuò)展功能建議
- 批量蓋章:支持在多個(gè)位置批量添加相同印章
- 印章庫(kù)管理:保存常用的多個(gè)印章,方便快速選擇
- 模板功能:保存常用的蓋章位置模板
- 文字水印:除了圖片印章,支持添加文字水印
- 多頁(yè)操作:支持跨頁(yè)復(fù)制印章位置
九、總結(jié)
通過(guò)這個(gè)項(xiàng)目,我們實(shí)現(xiàn)了:
- 一個(gè)完整的桌面GUI應(yīng)用
- PDF文件的解析和渲染
- 精確的坐標(biāo)定位系統(tǒng)
- 圖像與PDF的合成功能
- 友好的用戶(hù)交互界面
這個(gè)工具不僅實(shí)用,也是學(xué)習(xí)PyQt5圖形界面編程和PDF處理的好例子。
到此這篇關(guān)于使用Python開(kāi)發(fā)一個(gè)桌面版PDF蓋章工具的文章就介紹到這了,更多相關(guān)Python PDF蓋章工具內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Python自然語(yǔ)言處理停用詞過(guò)濾實(shí)例詳解
這篇文章主要為大家介紹了Python自然語(yǔ)言處理停用詞過(guò)濾實(shí)例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2024-01-01
Python Pandas學(xué)習(xí)之基本數(shù)據(jù)操作詳解
本文將通過(guò)讀取一個(gè)股票數(shù)據(jù),來(lái)進(jìn)行Pandas的一些基本數(shù)據(jù)操作的語(yǔ)法介紹。文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2022-02-02
詳解pandas映射與數(shù)據(jù)轉(zhuǎn)換
這篇文章主要介紹了pandas映射與數(shù)據(jù)轉(zhuǎn)換的相關(guān)資料,幫助大家更好的利用python進(jìn)行數(shù)據(jù)分析,感興趣的朋友可以了解下2021-01-01
Python中json文件和jsonl文件的區(qū)別小結(jié)
本文主要介紹了JSON和JSONL兩種文件格式的區(qū)別,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2025-01-01
Python編程tkinter庫(kù)Canvas實(shí)現(xiàn)涂鴉顏色表及圍棋盤(pán)示例
這篇文章主要為大家介紹了Python編程中如何使用tkinter庫(kù)Canvas來(lái)實(shí)現(xiàn)涂鴉,顏色表及圍棋盤(pán)的示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助2021-10-10
SymPy庫(kù)關(guān)于矩陣的基本操作和運(yùn)算
本文主要介紹了SymPy庫(kù)關(guān)于矩陣的基本操作和運(yùn)算,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2023-03-03
python udp如何實(shí)現(xiàn)同時(shí)收發(fā)信息
這篇文章主要介紹了python udp如何實(shí)現(xiàn)同時(shí)收發(fā)信息,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-05-05
一文詳解如何從根本上優(yōu)雅地解決VSCode中的Python模塊導(dǎo)入問(wèn)題
有時(shí)你可能會(huì)遇到這種問(wèn)題,明明用pip安裝好了一個(gè)python模塊,但在VScode中總是顯示錯(cuò)誤,這篇文章主要給大家介紹了關(guān)于如何從根本上優(yōu)雅地解決VSCode中的Python模塊導(dǎo)入問(wèn)題的相關(guān)資料,需要的朋友可以參考下2024-07-07
python報(bào)錯(cuò)TypeError: Input z must be
大家好,本篇文章主要講的是python報(bào)錯(cuò)TypeError: Input z must be 2D, not 3D的解決方法,感興趣的同學(xué)趕快來(lái)看一看吧,對(duì)你有幫助的話(huà)記得收藏一下2021-12-12

