先讀範圍,再決定 PDF 要讀、要轉,還是要遮。
PDF 工坊只在你的瀏覽器內處理檔案:不上傳、不使用瀏覽器儲存空間。本頁說明它做什麼、不做什麼、輸出檔怎麼組成、如何自行驗證,以及最常被誤解的地方。
先說清楚這不是什麼
這不是加密,不是數位簽章,也不是檔案真偽的鑑定。遮蔽後的檔案沒有密碼,拿到的人都能打開,看見所有沒被框起來的地方。
- 輸出是新檔案,不是原檔的修改版。原檔不會被改動。原檔若有數位簽章,影像版不會保留簽章;新檔與原檔內容不同,SHA-256 也不同。
- 黑色方塊不等於刪除文字。多數 PDF 編輯器加上黑色矩形後,底下的文字仍在檔案裡,仍可複製、搜尋,或把內容串流解壓縮後讀出。本工具的做法不同(見下面的規則細節),但它同樣只遮你框起來的地方。
- 自動掃描只是提醒。電話、Email、身分證樣式與長數字,是依文字的「形狀」找出來的;不驗證檢查碼、不查詢任何資料庫、不連網。沒找到不代表沒有;圖片、表單欄位與註解裡的字也不會被掃到。
- 檢查通過不代表你框對了地方。自我檢查只確認檔案結構、重新開啟後沒有文字、框內像素是黑的;框歪了、漏了一頁,檢查一樣會通過。請逐頁目視確認。
- 不提供解除密碼、移除限制或繞過保護的功能。有密碼的檔案要由你輸入密碼;密碼只在本機用來開啟檔案,不會被儲存,也不會輸出解密後的副本。本工具只處理你合法持有、或有權處理的檔案。
- 結果是輔助整理,不是法律意見。遮蔽後的檔案是否適合對外提供、是否符合法令或契約,請由律師或專業人員判斷。
讀文字
逐頁讀出 PDF 文字層裡的文字,附頁碼,可搜尋、複製與下載。
- 做什麼
- 用 pdf.js 一次處理一頁,每頁之間讓出畫面,可隨時取消。單檔上限 100 MiB、500 頁;抽出的文字合計上限 500 萬字,超過時會明確告知,不會悄悄截斷。
- 逐頁標示「有文字」「文字很少」(少於 10 個非空白字元)「無文字層」「疑似亂碼」,並列出沒有文字層的頁碼。掃描檔沒有文字層,請改用本站的 本機 OCR 工具。
- 全文搜尋(至多 200 字):顯示命中次數與分布的頁碼,並在內文標出。比對時全形與半形、大小寫視為相同。
- 複製全部文字、下載 TXT、下載 JSON(含頁碼、每頁字數與判定類型)。
- 「送到線索推理艙」:只在你的瀏覽器內,把文字傳給本站的另一個分頁,不經過任何伺服器。需要你點按,也需要允許開啟新視窗;送不出去時請改用複製。
- 不做什麼
- 不做 OCR,不辨識圖片裡的字。
- 不還原版面。表格與欄位的順序,以 PDF 內部記錄的文字順序為準,可能和畫面上看到的不同。
- 不上傳、不聯網、不使用任何瀏覽器儲存空間;關閉或重新整理頁面,畫面上的內容就消失。
- 規則細節
- 文字來自 PDF 內嵌的文字層,不是畫面上看到的字。有些 PDF(例如部分瀏覽器列印出來的中文)會把字對應到「康熙部首」等相容區的字元;本工具會把這幾個區段轉成一般字元再顯示與搜尋,仍可能與你看到的不同,這類頁面會被標為疑似亂碼。
- 搜尋時逐字做 NFKC 正規化並轉小寫,再把命中位置換算回原文,所以全形數字、英文字母也搜得到。
- 疑似亂碼的判斷:非空白字元中,有超過 20% 是替代字元、私用區字元或控制字元。這只是粗略的提醒,不是辨識準確度。
- 如何自行驗證
- 用另一個程式讀同一份檔,抽樣比對,例如:
pdftotext -layout 檔名.pdf -。兩者的換行與順序可能不同,字句應該相同。 - 下載的 JSON 格式為 gib-pdf-text-1,每頁一筆,含 page、kind、chars、text,可用任何程式讀取檢查。
- 用另一個程式讀同一份檔,抽樣比對,例如:
- 常見誤解
- 「沒抽到字」不等於「這頁沒有字」:很可能是掃描影像。
- 「抽到的字」不等於「畫面上看得到的字」:文字層可能是隱藏的(例如 OCR 後的掃描檔),位置也可能與畫面有落差。
- 匯出的 TXT 與 JSON 含檔名與全部文字,分享前請自行檢查是否含個資。
轉成圖片
把選定的頁面畫成 PNG 或 JPEG,逐頁下載,或打包成 ZIP。
- 做什麼
- 頁面範圍可寫成 1-3,5,8-10,或輸入「全部」。解析度可選 72、96、150、200 DPI。
- 單頁超過 1,600 萬像素(或單邊超過 16,384 像素)時,會自動降低解析度,並在每一頁旁標示實際用了多少;降到約 24 DPI 以下仍放不下的頁面會被略過並說明原因。
- PNG 無損、檔案較大;JPEG 檔案較小,有輕微壓縮。
- ZIP 是自己寫的「僅封裝、不壓縮」格式(圖片本身已經壓縮),檔名以 UTF-8 儲存,並計算 CRC-32。圖片合計超過 400 MiB 時會停止並告知,請縮小範圍或降低 DPI 後分批轉換。
- 不做什麼
- 不遮蔽任何內容;轉出的圖片就是頁面原樣(含表單欄位目前的值)。要遮蔽請用「安全遮蔽」。
- 不保留文字層、連結、書籤或註解的互動功能。
- 不上傳、不使用瀏覽器儲存空間。
- 規則細節
- 像素尺寸 = 頁面可見範圍(已考慮 CropBox、旋轉與 UserUnit)的點數 × DPI ÷ 72,四捨五入。
- pdf.js 以列印模式畫在白色底上,所以透明背景會變成白色。
- 如何自行驗證
- 用
unzip -t 檔名_圖片.zip(或任何解壓縮程式)檢查 ZIP,應該全部 OK。 - 用任何看圖程式開啟,並與原 PDF 在閱讀器中的樣子比對。不同閱讀器的字型與色彩處理略有差異是正常的。
- 用
- 常見誤解
- DPI 越高不代表越好:檔案與記憶體用量會隨之快速增加,手機上請從 96 或 150 開始。
- 轉成圖片後文字就無法複製,但不代表資料已被去識別化;圖片裡的內容仍然看得見。
安全遮蔽並影像化
在頁面上框出要遮住的地方,輸出一份每頁只有一張影像的新 PDF,並在本機立即自我檢查。
- 做什麼
- 用滑鼠或手指在頁面上拖曳畫框;框可以拖動、用四角調整大小,也可以用鍵盤移動與刪除。可復原、清除本頁的框,或把某個框的位置套用到所有頁。
- 可先掃描文字層裡的電話、Email、身分證樣式與長數字,在頁面上用橘色虛線標出;每一處都由你決定遮或不遮,不會自動套用。
- 每頁最多 200 個框、全檔最多 5,000 個框;DPI 可選 72、96、150、200;影像格式可選 JPEG 或 PNG(Flate 壓縮)。
- 輸出檔名建議為「原檔名_遮蔽版.pdf」,只是建議,可自行修改。
- 輸出後做 9 項自我檢查,並計算 SHA-256 與大小;全部通過才提供下載,任何一項沒過就不提供下載並說明原因。檢查通過後,可在頁面內逐頁檢視輸出檔,並顯示已檢視幾頁。
- 不做什麼
- 不加密、不簽章、不加浮水印、不產生任何密碼;輸出檔沒有文字層,無法搜尋或複製,通常比原檔大。
- 不修改原檔,也不覆蓋原檔:輸出一律是新檔案。
- 不自動決定要遮什麼。自動掃描只標記,不套用;掃描不到圖片、表單欄位與註解裡的字。
- 不輸出解密後的副本;不繞過密碼或使用限制。檔案若宣告了「不允許複製或列印」之類的限制,要先由你勾選確認有權處理,才會繼續。
- 不保留原檔的書籤、連結、註解、附件、表單、JavaScript、標題、作者、XMP 等任何中繼資料。
- 規則細節:最小 PDF 是怎麼組成的
- 座標:框以頁面「顯示方向」的比例(0 到 1,左上角為原點)記錄,所以放大縮小、換 DPI 都不會跑掉。輸出時換算成輸出影像的像素,向外取整,並再往外多留約 0.75 倍縮放比例(至少 1 像素)的邊,避免字的邊緣露出一圈。
- 繪製順序:先用 pdf.js 把整頁畫到畫布(含表單欄位目前的值),再直接把框內的像素改成純黑,然後才編碼成 JPEG 或 PNG。框內被蓋掉的內容在編碼前就已不存在,不是「蓋在上面」;JPEG 壓縮只會讓框的邊緣有輕微暈開。
- 檔案結構:由本頁自行撰寫的最小寫出器產生,不使用任何 PDF 函式庫:
%PDF-1.4 + 一行二進位註解 1 0 obj 目錄(Catalog) → /Pages 2 0 R 2 0 obj 頁面樹(Pages) → /Kids [4 0 R 7 0 R …] /Count n 3 0 obj 資訊字典(Info) → 只有 /Producer 與 /CreationDate 每一頁固定 3 個物件(第 i 頁為 4+3i、5+3i、6+3i): 頁面 /MediaBox [0 0 寬 高] /Resources << /XObject << /Im0 … >> >> /Contents … 內容串流 q 寬 0 0 高 0 0 cm /Im0 Do Q 影像 /Subtype /Image /ColorSpace /DeviceRGB /BitsPerComponent 8 JPEG:/Filter /DCTDecode(直接存放編碼後的 JPEG) PNG 選項:/Filter /FlateDecode /DecodeParms << /Predictor 15 … >> xref 傳統交叉參照表(每筆 20 位元組) trailer << /Size n /Root 1 0 R /Info 3 0 R >> startxref %%EOF沒有字型、沒有文字運算子、沒有註解、附件、JavaScript、表單、動作、物件串流、增量更新、加密或 XMP;頁面也沒有 /Rotate。 - 頁面尺寸:等於原頁的可見範圍:已考慮 CropBox、頁面旋轉(輸出為旋轉後看到的方向,不再帶 /Rotate)與 UserUnit。自我檢查會用 pdf.js 把輸出檔每頁的尺寸與原頁逐頁比對(誤差小於 0.01 pt)。
- 自我檢查的 9 項:① xref 偏移全部吻合,檔案內每個位元組都屬於標頭、物件、xref 或 trailer;② 物件字典中沒有 /JS、/JavaScript、/EmbeddedFile、/Annots、/OpenAction、/AcroForm;③ 所有名稱都在允許清單內;④ 每頁只有一個影像物件與一段「畫影像」的內容串流;⑤ pdf.js 重新開啟成功,頁數相同;⑥ 逐頁呼叫 getTextContent(),文字項目為 0;⑦ 註解、附件、表單欄位、JavaScript 都沒有;⑧ 頁面尺寸與原頁相同;⑨ 重新畫出輸出檔,取樣框內像素,確認是黑色。
- 如何自行驗證
- 用你信任的另一組工具,不依賴本站任何程式。先確認檔案與工具顯示的 SHA-256 一致,再確認沒有文字、沒有主動內容:
# 1. 檢查碼與結構 sha256sum 檔名_遮蔽版.pdf # 與頁面上顯示的 SHA-256 比對 qpdf --check 檔名_遮蔽版.pdf # 2. 沒有文字:預期只剩換頁字元(每頁 1 個) pdftotext 檔名_遮蔽版.pdf - | wc -c # 3. 物件結構裡沒有 JavaScript、附件、註解等(--json 不含串流資料,不會被影像的位元組誤判) qpdf --json --json-key=qpdf 檔名_遮蔽版.pdf | grep -c -E '"/(JS|JavaScript|EmbeddedFile|Annots|OpenAction|AcroForm|Font)"' # 預期輸出 0
- 用 Python(pikepdf 與 pypdf)逐頁檢查:
import pikepdf from pypdf import PdfReader path = "檔名_遮蔽版.pdf" pdf = pikepdf.open(path) print("資訊字典:", {k: str(v) for k, v in pdf.docinfo.items()}) # 只有 /Producer 與 /CreationDate for k in ("/Names", "/AcroForm", "/OpenAction", "/AA", "/Metadata", "/Outlines"): assert k not in pdf.Root, k for n, page in enumerate(pdf.pages, 1): res = page.Resources assert "/Font" not in res and "/Annots" not in page, n imgs = list(res.get("/XObject", {}).values()) assert len(imgs) == 1 and imgs[0].Subtype == "/Image", n print(n, [float(x) for x in page.MediaBox], imgs[0].Width, imgs[0].Height, imgs[0].Filter) r = PdfReader(path) assert sum(len(p.extract_text() or "") for p in r.pages) == 0 print("沒有文字層,共", len(r.pages), "頁") - 把你遮蔽的原文(例如電話號碼)拿去搜尋輸出檔:
grep -a -c "0912" 檔名_遮蔽版.pdf預期為 0;也可以用任何 PDF 閱讀器的搜尋功能,預期找不到。這只能證明「文字不在檔案裡」,不能證明「影像裡沒有露出」,後者要靠你的眼睛。 - 把輸出檔轉成圖片,與你標的框逐頁比對;最後再用不同的閱讀器開啟看一次。
- 用你信任的另一組工具,不依賴本站任何程式。先確認檔案與工具顯示的 SHA-256 一致,再確認沒有文字、沒有主動內容:
- 常見誤解
- 「黑色方塊蓋上去就是刪掉了。」不是。蓋在上面的方塊底下仍有原文,複製貼上、搜尋、解壓縮內容串流都可能讀回來。本工具改為把框內的像素改成黑色,再輸出沒有文字層的影像版,原文不會留在檔案裡。
- 「輸出是影像,所以一定安全。」不是。沒被框到的字都還在影像裡;框偏了、框小了、漏了某一頁,字就會露出來。頁首頁尾、浮水印、圖章、手寫字、縮小的附註也常被漏掉。
- 「9 項檢查通過就可以放心分享。」檢查只能證明檔案「乾淨」,不能證明你「框對」。請用頁面內的逐頁檢視,把每一頁都看過。
- 「OCR 可以還原被遮住的字。」被框住的像素已經是純黑,OCR 無從還原;但沒被框住的字,OCR 可以讀出,輸出檔也可能被別人再 OCR 成可搜尋的文字。
- 「檔名有 _遮蔽版 就代表處理過。」檔名只是建議;是否處理過,以檔案內容與你自己的檢查為準。
- 「輸出檔會比較小。」通常相反:每頁是一張影像,比原本的文字與向量圖大,而且無法搜尋、複製。
- 「SHA-256 相同就代表內容沒被動過。」只代表位元組相同,與內容是否真實無關。
實測參考(本機沙箱小樣本)
下列數字是在開發用的沙箱環境,以 Chromium 小量樣本實測得到,只說明這個工具在該環境的表現,不代表你的裝置;不是規格,也不是承諾。
| 項目 | 條件 | 結果 |
|---|---|---|
| 開檔+文字層檢查 | 3 頁中文檔 | 0.61 秒 |
| 開檔+文字層檢查 | 100 頁 | 1.2 秒 |
| 開檔+文字層檢查 | 500 頁(簡單文字頁) | 1.2 秒 |
| 讀文字 | 100 頁 | 0.17 秒 |
| 轉成圖片 | 100 頁、72 DPI、JPEG | 2.6 秒 |
| 轉成圖片 | 100 頁、72 DPI、PNG | 2.6 秒 |
| 安全遮蔽輸出(含自我檢查) | 100 頁、200 個框、JPEG 150 DPI | 9.2 秒,輸出 12.0 MiB |
| 安全遮蔽輸出(含自我檢查) | 100 頁、200 個框、PNG 96 DPI | 9.2 秒,輸出 5.93 MiB |
| 安全遮蔽輸出(含自我檢查) | 100 頁、200 個框、JPEG 200 DPI | 13.6 秒,輸出 18.3 MiB |
| 記憶體 | 上列 JPEG 150 DPI 的輸出期間 | JavaScript 堆積 17 → 尖峰 20 MB;瀏覽器全部程序合計 637 → 尖峰 1,119 MB |
| 取消 | 輸出到 24 / 100 頁時按「取消」 | 0.10 秒內停止,畫面顯示「已取消,沒有產生檔案。」 |
| 主執行緒長任務 | 一般頁面的全部步驟 | 超過 100 毫秒的有 0 個(最長 82 毫秒) |
| 極大頁面 | A0 尺寸頁(需自動降低解析度) | 輸出 1.0 秒;主執行緒出現 113、107 毫秒的長任務(已知限制) |
| 超過單頁上限 | 14400 × 14400 pt 的頁面 | 直接拒絕並說明原因,不產生檔案 |
| CPU 降為 1/4 速度 | 開檔+文字層檢查,3 頁 / 100 頁 | 1.1 秒 / 3.6 秒 |
| CPU 降為 1/4 速度 | 掃描可疑文字,100 頁 | 2.1 秒 |
| CPU 降為 1/4 速度 | 3 頁遮蔽輸出,JPEG / PNG 150 DPI | 1.3 秒 / 2.1 秒 |
| CPU 降為 1/4 速度 | 20 頁、40 個框、JPEG 150 DPI | 8.3 秒,輸出 2.39 MiB |
| CPU 降為 1/4 速度 | 上列 20 頁輸出的記憶體 | JavaScript 堆積 19 → 尖峰 20 MB;瀏覽器全部程序合計 586 → 尖峰 760 MB |
| CPU 降為 1/4 速度 | 主執行緒長任務 | 最長 132 毫秒(出現在「開檔」步驟),其餘步驟最長 81 毫秒 |
環境:2 核心、Chromium 141(無頭模式);測試時機器上可能同時有其他工作(開始時的 1 分鐘負載平均:一般速度 1.84、降速 1.46)。「降為 1/4 速度」是用瀏覽器的開發者工具協定模擬,不等於真實的低階手機。每項只量一到數次,不具統計意義;記憶體數字含瀏覽器本身,會隨作業系統與瀏覽器版本而不同。長任務指主執行緒連續忙碌超過 50 毫秒的片段;超過 100 毫秒時,畫面可能短暫停頓。
建議的使用流程
- 保留原檔,不要覆蓋;輸出一律另存新檔。
- 先到「讀文字」看這份 PDF 有沒有文字層;掃描檔沒有文字層,自動掃描對它無效,要自己畫框。
- 到「安全遮蔽」,先按「掃描可疑文字」,逐一決定遮或不遮;再逐頁自己看一遍,補上掃描找不到的地方(圖片、手寫、圖章、頁首頁尾、浮水印)。
- 輸出設定先用 150 DPI 的 JPEG;手機記憶體有限時降到 96 或 72,或分段輸出頁面範圍。
- 等 9 項自我檢查跑完,再用頁面內的檢視逐頁看過輸出檔,確認每個該遮的地方都是黑的。
- 用上面的指令或 Python,自己再驗證一次;把遮蔽版與原檔分開存放,只分享遮蔽版。
- 是否適合對外提供、是否符合法令或契約,請諮詢律師或專業人員。
已知限制與不確定處
- PDF 由內建的 pdf.js 6.4.299(Apache-2.0,採用相容舊瀏覽器的版本)在本機繪製。罕見字型、特殊色彩或損毀的檔案,畫出來的樣子可能與其他閱讀器不同;輸出檔以「這個工具畫出來的樣子」為準,所以必須逐頁目視確認。
- 只在 Chromium 內做過實測;其他瀏覽器沒有在沙箱中測試,請自行小量試用並檢查輸出。需要較新的瀏覽器(約近三年的版本)。
- 自動建議的框位置,是依文字層的位置與字寬估算,會多留一點邊;文字層與畫面不一致的檔案(例如 OCR 後的掃描檔)可能偏移,請一律以目視為準。
- 單頁上限 1,600 萬像素、遮蔽輸出合計上限 400 MiB、單檔 100 MiB、500 頁。手機的記憶體差異很大,超過裝置能力時瀏覽器可能直接中止分頁;請降低 DPI 或分段處理。
- 接近單頁上限的超大頁面(例如 A0 尺寸,約 1,600 萬像素)在輸出時,畫面可能短暫停頓 0.1 秒上下;數字見上方「實測參考」,是本機沙箱小樣本,換一台裝置會不同。一般大小的頁面在同樣的測試中沒有出現。
- 輸出檔沒有書籤、連結與文字層,也不是 PDF/A。