Trong quá trình quản lý tài liệu, kho dữ liệu kỹ thuật hoặc website, bạn thường xuyên phải đối mặt với các file PDF có dung lượng “khủng” nằm rải rác trong nhiều thư mục con. Việc mở từng file để nén thủ công vô cùng mất thời gian.
Bài viết này sẽ hướng dẫn bạn cách sử dụng Ghostscript kết hợp với PowerShell trên Windows 11 để tự động hóa hoàn toàn quy trình nén file PDF theo cấu trúc cây thư mục với 2 kịch bản linh hoạt: Xuất ra thư mục nén độc lập hoặc Nén đè trực tiếp lên file gốc.
Phần 1: Cài đặt Ghostscript trên Windows 11
Trước tiên, bạn cần trang bị công cụ cốt lõi là Ghostscript.
- Tải bộ cài: Truy cập trang chủ Ghostscript và tải phiên bản GPL Ghostscript mới nhất (ví dụ bản
10.08.0cho Windows 64-bit). Link: Ghostscript : Releases - Tiến hành cài đặt: Chạy file cài đặt và giữ nguyên đường dẫn mặc định khuyên dùng để tránh sai sót cấu trúc:
C:\Program Files\gs\gs10.08.0\bin\gswin64c.exe
Phần 2: Kịch bản 1 — Nén hàng loạt và lưu vào Thư mục Đích riêng
Cách này phù hợp khi bạn muốn giữ nguyên vẹn toàn bộ thư mục gốc và tạo một bản sao đã được nén tối ưu vào một nơi khác (vẫn giữ nguyên cấu trúc thư mục con bên trong).
Sử dụng phần mềm PowerShell có sẵn trong Windows
Script PowerShell hoàn chỉnh:
# Định nghĩa đường dẫn nguồn, đích và file thực thi Ghostscript
$sourceDir = "D:\Downloads"
$outputDir = "D:\Downloads_Compressed"
$gsPath = "C:\Program Files\gs\gs10.08.0\bin\gswin64c.exe"
# Quét tất cả file PDF (không phân biệt chữ hoa/thường, hỗ trợ thư mục con)
$files = Get-ChildItem -Path $sourceDir -Recurse | Where-Object { $_.Extension -eq '.pdf' -or $_.Extension -eq '.PDF' }
Write-Host "Tìm thấy $($files.Count) file PDF cần nén." -ForegroundColor Cyan
foreach ($file in $files) {
# Tái tạo lại cấu trúc thư mục con
$relativePath = $file.DirectoryName.Substring($sourceDir.Length)
$destFolder = Join-Path $outputDir $relativePath
if (-not (Test-Path $destFolder)) {
New-Item -ItemType Directory -Force -Path $destFolder | Out-Null
}
$destFile = Join-Path $destFolder $file.Name
# Gọi Ghostscript qua .NET Process (chọn mức độ nén /printer hoặc /ebook, /screen)
$arguments = "-sDEVICE=pdfwrite -dCompatibilityLevel=1.5 -dPDFSETTINGS=/printer -dNOPAUSE -dQUIET -dBATCH -sOutputFile=`"$destFile`" `"$($file.FullName)`""
$process = [System.Diagnostics.Process]::Start($gsPath, $arguments)
$process.WaitForExit()
}
Write-Host "Đã hoàn tất quá trình nén và lưu vào thư mục đích!" -ForegroundColor Green
Phần 3: Kịch bản 2 — Nén đè trực tiếp lên file hiện tại
Nếu dung lượng ổ đĩa hạn chế và bạn muốn nén trực tiếp các file PDF để giảm dung lượng ngay trong thư mục làm việc (áp dụng cho mọi tầng thư mục con, thư mục cháu), hãy sử dụng script dưới đây.
Cơ chế an toàn: Script sẽ nén ra một file tạm (.tmp.pdf) trước, sau khi thành công mới tiến hành thay thế file gốc, đồng thời tự động xử lý an toàn các tên file chứa ký tự đặc biệt như dấu cách hoặc dấu %.
Script PowerShell nén đè đa cấp:
# Định nghĩa thư mục gốc cần nén đè và đường dẫn Ghostscript
$sourceDir = "D:\Duong_Dan_Thu_Muc_Cua_Ban"
$gsPath = "C:\Program Files\gs\gs10.08.0\bin\gswin64c.exe"
# Quét toàn bộ file PDF đệ quy đa cấp
$files = Get-ChildItem -Path $sourceDir -Recurse | Where-Object { $_.Extension -eq '.pdf' -or $_.Extension -eq '.PDF' }
Write-Host "Tìm thấy $($files.Count) file PDF cần nén đè." -ForegroundColor Cyan
foreach ($file in $files) {
$originalPath = $file.FullName
$tempFile = "$originalPath.tmp.pdf"
# Xử lý an toàn ký tự đặc biệt % (nếu có trong tên file)
$gsOutputFile = $tempFile.Replace('%', '%%')
# Thực thi Ghostscript với mức nén /printer (cân bằng chất lượng in ấn và dung lượng)
$arguments = "-sDEVICE=pdfwrite -dCompatibilityLevel=1.5 -dPDFSETTINGS=/printer -dNOPAUSE -dQUIET -dBATCH -sOutputFile=`"$gsOutputFile`" `"$originalPath`""
$process = [System.Diagnostics.Process]::Start($gsPath, $arguments)
$process.WaitForExit()
# Kiểm tra file tạm hợp lệ rồi tiến hành ghi đè
if ((Test-Path $tempFile) -and ((Get-Item $tempFile).Length -gt 0)) {
Remove-Item $originalPath -Force
Rename-Item $tempFile -NewName $file.Name
Write-Host "Đã nén đè thành công: $originalPath" -ForegroundColor Green
} else {
if (Test-Path $tempFile) { Remove-Item $tempFile -Force }
Write-Host "Lỗi khi nén file: $originalPath" -ForegroundColor Red
}
}
Write-Host "Hoàn tất toàn bộ quá trình nén đè các cấp thư mục!" -ForegroundColor Green
Phần 4: Tùy chỉnh các cấp độ nén
Trong các đoạn script trên, tham số -dPDFSETTINGS=/printer có thể thay đổi tùy thuộc vào mục đích sử dụng của bạn:
/printer: Chất lượng cao, tối ưu hóa hình ảnh cho việc in ấn văn phòng (khuyên dùng cho tài liệu kỹ thuật, báo giá)./ebook: Cân bằng tốt giữa dung lượng và độ nét, thích hợp để đọc trên máy tính hoặc máy tính bảng./screen: Mức nén mạnh nhất, dung lượng file siêu nhẹ (giảm độ phân giải ảnh xuống 72 DPI), phù hợp gửi email nhanh./prepress: Chất lượng gần như nguyên bản, dung lượng giảm rất ít (dành cho nhà in chuyên nghiệp).
💡 Lưu ý quan trọng: Bạn chỉ nên chạy nén 1 lần duy nhất từ file gốc. Việc đem một file đã bị nén giảm chất lượng đi nén lại nhiều lần sẽ làm hình ảnh bên trong bị vỡ hạt và giảm chất lượng nghiêm trọng.






