畢業論文超清pdf帶標簽導出

Word直接導出的pdf不夠清晰,使用打印導出的pdf又不帶書簽以及目錄跳轉功能這一問題,查閱網上資料使用Adobe DC似乎能夠解決但是下載安裝比較麻煩,于是寫了python程序解決該問題。

解決思路: 使用python腳本對兩個pdf文件進行合并,合并小體積的帶書簽的pdf和高清版本的pdf文件。

Step1:準備帶書簽的pdf,并命名為999.pdf (該名稱與程序對應)

使用word導出功能,選擇最小文件導出,并勾選書簽導出選項。

Step2:打印輸出高清pdf文件,并命名為a.pdf

打印使用福昕pdf的虛擬打印機,最高支持2400dpi的清晰度,我一般選1200dpi,已經足夠清晰了。(也可以使用自帶的Microsoft pdf 打印輸出 但最高只支持600dpi)

打印導出文件,并命名為a.pdf

如果遇到導出的pdf文件太大可以不勾選word選項中的“不壓縮文件中的圖像”來進一步限制打印輸出文件大小。

###使用Microsoft pdf打印輸出文件也可以用代碼替代執行,但最高只有600dpi,不如福昕pdf

import win32com.client
from pathlib import Path
import os
import timedef convert_docx_to_hd_pdf(input_docx, output_pdf):# 確保輸出路徑存在output_path = Path(output_pdf).parentos.makedirs(output_path, exist_ok=True)# 創建Word應用對象word = win32com.client.DispatchEx("Word.Application")word.Visible = Truetry:# 打開文檔doc = word.Documents.Open(str(Path(input_docx).resolve()))# 獲取文檔總頁數total_pages = doc.ComputeStatistics(2)  # 2 = wdStatisticPagesprint(f"文檔共 {total_pages} 頁,開始轉換...")# 輸出路徑output_pdf_abs = str(Path(output_pdf).resolve())# 設置打印機為Microsoft Print to PDFword.ActivePrinter = "Microsoft Print to PDF"# 設置打印選項word.Options.PrintBackground = Trueword.Application.Options.PrintDraft = Falseword.Application.Options.PrintProperties = False# 執行打印print("開始高質量打印...")word.ActiveDocument.PrintOut(OutputFileName=output_pdf_abs,Range=0,Item=0,Copies=1,Pages="",PageType=0,PrintToFile=True,Collate=False)# 等待打印完成print("正在等待打印完成...")# 等待文件生成max_wait = 30  # 最多等待30秒start_time = time.time()while time.time() - start_time < max_wait:if os.path.exists(output_pdf) and os.path.getsize(output_pdf) > 0:print(f"PDF導出完成: {output_pdf}")print(f"文件大小: {os.path.getsize(output_pdf)} 字節")return Truetime.sleep(1)print("等待超時,請檢查輸出文件")return Falseexcept Exception as e:print(f"轉換失敗: {str(e)}")return Falsefinally:try:doc.Close(SaveChanges=False)except:password.Quit()# 執行轉換
if __name__ == "__main__":convert_docx_to_hd_pdf('88.docx', '999.pdf')  ## 88.docx為word文件名

總之會得到兩個pdf文件如下

Step3:創建虛擬環境,并執行文件合并

conda create -n xxx python=3.9conda activate xxxcd xxxxxpip install pikepdf pathlib os

然后運行程序,在此之前需在程序中指定目錄頁碼范圍,比如我的word目錄對應9-10頁

修改如下部分

運行

import pikepdf
from pathlib import Path
import osstart_page = 8
end_page = 9def merge_pdfs_with_bookmarks(image_pdf_path, bookmark_pdf_path, output_pdf_path):"""合并兩個PDF文件,保留第二個PDF的書簽信息和目錄頁,其他頁面使用第一個PDF的內容參數:image_pdf_path: 包含高質量圖片的PDF路徑bookmark_pdf_path: 包含書簽信息的PDF路徑output_pdf_path: 輸出PDF的路徑"""print(f"開始合并PDF文件...")print(f"圖片源PDF: {image_pdf_path}")print(f"書簽源PDF: {bookmark_pdf_path}")try:# 確保輸出目錄存在output_dir = Path(output_pdf_path).parentos.makedirs(output_dir, exist_ok=True)# 打開兩個PDF文件with pikepdf.open(image_pdf_path) as image_pdf, pikepdf.open(bookmark_pdf_path) as bookmark_pdf:# 檢查頁數是否一致if len(image_pdf.pages) != len(bookmark_pdf.pages):print(f"警告: 兩個PDF的頁數不一致! 圖片PDF: {len(image_pdf.pages)}頁, 書簽PDF: {len(bookmark_pdf.pages)}頁")print("繼續合并,但可能導致書簽指向錯誤的頁面")# 創建一個新的PDF,以bookmark_pdf為基礎merged_pdf = pikepdf.Pdf.open(bookmark_pdf_path)# 創建頁面映射表,記錄原始頁面和新頁面的對應關系page_map = {}# 替換除了第8-9頁以外的所有頁面for i in range(len(merged_pdf.pages)):# 頁碼從0開始,所以第9-10頁對應索引8-9if (i > end_page or  i < start_page) and i < len(image_pdf.pages): # i != 10-12# 保存原始頁面的引用old_page = merged_pdf.pages[i]old_objgen = old_page.obj.objgen# 使用正確的方法替換頁面# pikepdf不支持直接刪除頁面,但可以直接替換merged_pdf.pages[i] = pikepdf.Page(image_pdf.pages[i])# 記錄頁面映射關系page_map[old_objgen[0]] = merged_pdf.pages[i].obj# 修復文檔內部鏈接(目錄頁鏈接)print("正在修復文檔內部鏈接...")# 特別處理目錄頁(第9-10頁,索引8-9)for i in [start_page, end_page]:if '/Annots' in merged_pdf.pages[i]:annots = merged_pdf.pages[i]['/Annots']if isinstance(annots, pikepdf.Array):# print(annots)for annot in annots:# 檢查是否是鏈接注釋if annot.get('/Subtype') == '/Link':# 處理直接目標if '/Dest' in annot:dest = annot['/Dest']if isinstance(dest, pikepdf.Array) and len(dest) > 0:if hasattr(dest[0], 'objgen'):ref_id = dest[0].objgen[0]if ref_id in page_map:dest[0] = page_map[ref_id]# 處理動作目標elif '/A' in annot and isinstance(annot['/A'], pikepdf.Dictionary) and '/D' in annot['/A']:dest = annot['/A']['/D']if isinstance(dest, pikepdf.Array) and len(dest) > 0:if hasattr(dest[0], 'objgen'):ref_id = dest[0].objgen[0]if ref_id in page_map:dest[0] = page_map[ref_id]# 提取書簽信息bookmarks = []if hasattr(bookmark_pdf, 'Root') and '/Outlines' in bookmark_pdf.Root:print("正在提取書簽信息...")# 遞歸提取書簽def extract_bookmarks(outline, bookmarks, depth=0):if '/First' not in outline:returncurrent = outline['/First']while True:title = str(current.get('/Title', ''))dest = current.get('/Dest', None)page_num = 0if dest is not None and isinstance(dest, pikepdf.Array) and len(dest) > 0:# 查找目標頁面page_ref = dest[0]for i, page in enumerate(bookmark_pdf.pages):# 使用對象ID比較而不是same_as方法if hasattr(page.obj, 'objgen') and hasattr(page_ref, 'objgen'):if page.obj.objgen == page_ref.objgen:page_num = ibreak# 創建書簽項bookmark = {'title': title,'page': page_num,'children': []}bookmarks.append(bookmark)# 處理子書簽if '/First' in current:extract_bookmarks(current, bookmark['children'], depth + 1)# 移動到下一個書簽if '/Next' not in current:breakcurrent = current['/Next']# 提取所有書簽extract_bookmarks(bookmark_pdf.Root['/Outlines'], bookmarks)print(f"提取了 {len(bookmarks)} 個頂級書簽")# 如果有提取到書簽,添加到新PDFif bookmarks:print("正在將書簽添加到新PDF...")# 遞歸創建書簽def create_bookmarks(pdf, bookmarks, parent=None):if not bookmarks:return Nonefirst = Nonelast = Noneprev = Nonefor bookmark in bookmarks:# 創建新書簽current = pdf.make_indirect(pikepdf.Dictionary({'/Title': pikepdf.String(bookmark['title']),'/Parent': parent}))# 設置目標頁面page_idx = bookmark['page']if page_idx < len(pdf.pages):dest = [pdf.pages[page_idx].obj, pikepdf.Name('/Fit')]current['/Dest'] = pdf.make_indirect(pikepdf.Array(dest))# 處理鏈接關系if first is None:first = currentif prev is not None:prev['/Next'] = currentcurrent['/Prev'] = prevprev = currentlast = current# 處理子書簽if bookmark['children']:children_first = create_bookmarks(pdf, bookmark['children'], current)if children_first:current['/First'] = children_first# 找到最后一個子書簽children_last = children_firstwhile '/Next' in children_last:children_last = children_last['/Next']current['/Last'] = children_lastcurrent['/Count'] = len(bookmark['children'])return first# 創建書簽字典outlines = merged_pdf.make_indirect(pikepdf.Dictionary({'/Type': pikepdf.Name('/Outlines'),'/Count': len(bookmarks)}))# 創建書簽樹first = create_bookmarks(merged_pdf, bookmarks, outlines)if first:outlines['/First'] = first# 找到最后一個書簽last = firstwhile '/Next' in last:last = last['/Next']outlines['/Last'] = last# 添加到PDFmerged_pdf.Root['/Outlines'] = outlinesprint("成功添加書簽到新PDF")# 保存合并后的PDFmerged_pdf.save(output_pdf_path)print(f"PDF合并完成! 輸出文件: {output_pdf_path}")print(f"文件大小: {os.path.getsize(output_pdf_path)} 字節")return Trueexcept Exception as e:print(f"合并PDF時出錯: {str(e)}")import tracebacktraceback.print_exc()return Falseif __name__ == "__main__":# 文件路徑image_pdf = ".\a.pdf"  # 包含高質量圖片的PDFbookmark_pdf = ".\999.pdf"  # 包含書簽信息的PDFoutput_pdf = ".\out.pdf"  # 輸出文件# 執行合并merge_pdfs_with_bookmarks(image_pdf, bookmark_pdf, output_pdf)

大功告成

該文件大小一般與高清pdf文件大小相當...

特別說明:該程序對正文中的圖跳轉未作程序編寫。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/76885.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/76885.shtml
英文地址,請注明出處:http://en.pswp.cn/web/76885.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

NOIP2012提高組.同余方程

目錄 題目算法標簽: 數論, 擴展歐幾里得算法思路代碼 題目 203. 同余方程 算法標簽: 數論, 擴展歐幾里得算法 思路 簡單的擴展歐幾里得算法應用題, 擴展歐幾里得算法可以直接計算同余方程的通解, 因為求得是最小正整數解, 因此需要取模轉換為正整數 a x b y ≡ 1 ax by …

C++學習-入門到精通-【0】計算機和C++簡介

C學習-入門到精通-[0]計算機和C簡介 計算機和C簡介 C學習-入門到精通-[0]計算機和C簡介一、計算機的組成二、硬件和軟件三、數據的層次結構四、機器語言、匯編語言和高級語言五、C標準庫六、面向對象技術 一、計算機的組成 計算機是由多個不同功能的邏輯單元組成的&#xff1a…

macOS 系統設置息屏情況下,PHP等后臺腳本繼續執行

在 macOS 系統下&#xff0c;當屏幕息屏或合上蓋子時&#xff0c;后臺腳本程序是否會繼續運行&#xff0c;主要取決于以下幾個因素&#xff1a; 1. 系統睡眠狀態的影響 默認情況&#xff1a;合蓋/息屏后&#xff0c;Mac 會進入「睡眠模式」&#xff08;部分硬件休眠&#xff…

SpringBoot集成ActiveMQ異常處理機制:若未捕獲異常,消息會被重新投遞

一、問題描述 SpringBoot項目集成AvtiveMQ&#xff0c;作為消息消費者。如果在消費消息的方法中&#xff0c;拋出異常&#xff0c;會產生什么效果&#xff1f; 二、ActiveMQ異常處理機制&#xff08;AI問答僅供參考&#xff09; 在Spring Boot項目集成ActiveMQ作為消息消費者…

【Java學習筆記】random的使用

random使用方法 使用說明&#xff1a;返回的是(0<n<1)這個范圍中的任意帶正號的double值 代碼實例 public class helloworld{public static void main(String[] args){System.out.println(Math.random());} }生成0-100中的任意數代碼示例 public class Main {public …

(三)垂直分庫架構、分布式數據庫

文章目錄 垂直分庫架構/分布式數據庫什么是垂直分庫架構架構模型優缺點優點缺點 技術案例分布式數據庫架構模型優缺點優點缺點 技術案例 垂直分庫架構/分布式數據庫 什么是垂直分庫架構 根據業務的模塊劃分&#xff0c; 將不同業務的數據放到不同的數據庫中。 比如一個電子商城…

數據結構線性表的順序存儲結構

線性表是由零個或多個數據元素組成的有序序列。 特點&#xff1a; 數據元素間是有順序的&#xff1b; 數據元素的個數是有限的&#xff1b; 一般來說&#xff0c;數據元素的類型是相同的&#xff08;強類型語言&#xff09;。c/c是強類型語言&#xff0c;必須指定數據類型。…

扣子空間試用:生成五一騎行規劃+notion文章編寫

今天試用了一下扣子空間&#xff0c;正好五一快到了&#xff0c;讓它幫忙做了五一騎行規劃&#xff0c;效果不賴&#xff01; 生成五一騎行規劃 點擊前往網站查看效果 prompt 如下&#xff1a; 幫我做一個五一上海騎行規劃 要求&#xff1a; - 風景優美 - 人少 - 100km總路程…

最新得物小程序sign簽名加密,請求參數解密,響應數據解密逆向分析

點擊精選&#xff0c;出現https://app.dewu.com/api/v1/h5/index/fire/index 這個請求 直接搜索sign的話不容易定位 直接搜newAdvForH5就一個&#xff0c;進去再搜sign&#xff0c;打上斷點 可以看到t.params就是沒有sign的請求參數&#xff0c; 經過Object(a.default)該函數…

在C#串口通信中,一發一收的場景,如何處理不同功能碼的幀數據比較合理,代碼結構好

在 C# 串口通信的一發一收場景里&#xff0c;處理不同功能碼的幀數據可采用以下合理的代碼結構&#xff0c;它能讓代碼更具可讀性、可維護性和可擴展性。 實現思路 定義幀結構&#xff1a;創建一個類來表示通信幀&#xff0c;其中包含功能碼、數據等信息。功能碼處理邏輯&…

【C++】vector擴容縮容

vector擴容縮容 1 擴容 一般來說&#xff0c;主要是重新分配內存 2 縮容 resize 縮小后&#xff0c;vector 的容量&#xff08;capacity()&#xff09;可能保持不變&#xff0c;需要顯式調用 shrink_to_fit() 來釋放內存。 驗證代碼&#xff1a; #include <vector>…

java中,線程的執行狀態有哪些

在 Java 里&#xff0c;線程有 6 種執行狀態&#xff0c;這些狀態都在 java.lang.Thread.State 枚舉類中被定義。下面為你詳細介紹這些狀態&#xff1a; 1. NEW&#xff08;新建狀態&#xff09; 當你創建了一個 Thread 對象&#xff0c;卻還未調用其 start() 方法時&#xf…

MATLAB 控制系統設計與仿真 - 41

魯棒控制的其他函數 - 回路成型函數 loopsyn 靈敏度問題由魯棒控制工具箱中的loopsyn就可以直接求解,該函數采用H無窮回路成型算法設計控制器,函數的調用格式為: [K,CL,gamma,info] = loopsyn(G,Gd) % G為受控對象模型% Gd為期望的回路傳遞函數% K為回路成型控制器模型% C…

查詢Hologres或postgresql中的數據

因Hologres使用postgresql的語法.所以兩者查詢一樣. 方案1: import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; import java.util.ArrayList; import java.util.List;/*** 一個使用簡單連接池管理PostgreSQL連接的工具類。*/ publi…

OpenBayes 一周速覽|EasyControl 高效控制 DiT 架構,助力吉卜力風圖像一鍵生成;TripoSG 單圖秒變高保真 3D 模型

公共資源速遞 10 個教程&#xff1a; * 一鍵部署 R1-OneVision * UNO&#xff1a;通用定制化圖像生成 * TripoSG&#xff1a;單圖秒變高保真 3D * 使用 VASP 進行機器學習力場訓練 * InfiniteYou 高保真圖像生成 Demo * VenusFactory 蛋白質工程設計平臺 * Qwen2.5-0mni…

中興云電腦W102D_晶晨S905X2_2+16G_mt7661無線_安卓9.0_線刷固件包

中興云電腦W102D_晶晨S905X2_216G_mt7661無線_安卓9.0_線刷固件包 準備工作&#xff1a; 工具和設備在開始刷機之前&#xff0c;確保你已經準備好以下物品&#xff1a;雙公頭USB線&#xff1a;選擇一根30-50厘米長的USB線&#xff0c;長度適中&#xff0c;方便操作&#xff0c;…

Rust 學習筆記:安裝 Rust

Rust 學習筆記&#xff1a;安裝 Rust Rust 學習筆記&#xff1a;安裝 Rust在 Windows 上安裝 Rust命令行創建 Rust 項目在 Mac/Linux 上安裝 Rust一些命令升級卸載cargo -hrustc -h 安裝 RustRoverrust-analyzer Rust 學習筆記&#xff1a;安裝 Rust 在 Windows 上安裝 Rust …

Opencv圖像處理:輪廓檢測、輪廓近似、繪制外接圓外接矩形

文章目錄 一、圖像輪廓檢測1、比較2、常見的輪廓檢測方法1&#xff09;基于梯度的方法2&#xff09;基于邊緣檢測器的方法3&#xff09;基于閾值的方法 3、查找輪廓與繪制輪廓4、參數解釋4、代碼解釋1&#xff09;讀取原圖像灰度圖并用二值化顯示2&#xff09;輪廓繪制3&#x…

精益數據分析(17/126):精益畫布與創業方向抉擇

精益數據分析&#xff08;17/126&#xff09;&#xff1a;精益畫布與創業方向抉擇 大家好&#xff01;一直以來&#xff0c;我都希望能和大家一起在創業和數據分析的領域中不斷探索、共同進步。今天&#xff0c;我們接著深入學習《精益數據分析》&#xff0c;這次聚焦于精益畫…

每天五分鐘深度學習PyTorch:圖像的處理的上采樣和下采樣

本文重點 在pytorch中封裝了上采樣和下采樣的方法,我們可以使用封裝好的方法可以很方便的完成采樣任務,采樣分為上采樣和下采樣。 上采樣和下采樣 下采樣(縮小圖像)的主要目的有兩個:1、使得圖像符合顯示區域的大小;2、生成對應圖像的縮略圖。 下采樣( 放大圖像)的…