feat: fix bug for remove blank pages tool. added i18n translations

This commit is contained in:
alam00000
2026-03-03 23:34:55 +05:30
parent 5fbf48601e
commit 2aaea50031
19 changed files with 314 additions and 252 deletions

View File

@@ -163,7 +163,8 @@
}, },
"removeBlankPages": { "removeBlankPages": {
"name": "إزالة الصفحات الفارغة", "name": "إزالة الصفحات الفارغة",
"subtitle": "اكتشاف وحذف الصفحات الفارغة تلقائيًا." "subtitle": "اكتشاف وحذف الصفحات الفارغة تلقائيًا.",
"sensitivityHint": "أعلى = أكثر صرامة، فقط الصفحات الفارغة تمامًا. أقل = يسمح بصفحات تحتوي على بعض المحتوى."
}, },
"imageToPdf": { "imageToPdf": {
"name": "صور إلى PDF", "name": "صور إلى PDF",

View File

@@ -163,7 +163,8 @@
}, },
"removeBlankPages": { "removeBlankPages": {
"name": "Выдаліць пустыя старонкі", "name": "Выдаліць пустыя старонкі",
"subtitle": "Аўтаматычна выявіць і выдаліць пустыя старонкі." "subtitle": "Аўтаматычна выявіць і выдаліць пустыя старонкі.",
"sensitivityHint": "Вышэй = больш строга, толькі цалкам пустыя старонкі. Ніжэй = дапускае старонкі з нейкім змесцівам."
}, },
"imageToPdf": { "imageToPdf": {
"name": "Відарысы ў PDF", "name": "Відарысы ў PDF",

View File

@@ -163,7 +163,8 @@
}, },
"removeBlankPages": { "removeBlankPages": {
"name": "Fjern tomme sider", "name": "Fjern tomme sider",
"subtitle": "Find og fjern automatisk tomme sider." "subtitle": "Find og fjern automatisk tomme sider.",
"sensitivityHint": "Højere = strengere, kun helt tomme sider. Lavere = tillader sider med noget indhold."
}, },
"imageToPdf": { "imageToPdf": {
"name": "Billeder til PDF", "name": "Billeder til PDF",

View File

@@ -163,7 +163,8 @@
}, },
"removeBlankPages": { "removeBlankPages": {
"name": "Leere Seiten entfernen", "name": "Leere Seiten entfernen",
"subtitle": "Leere Seiten automatisch erkennen und löschen." "subtitle": "Leere Seiten automatisch erkennen und löschen.",
"sensitivityHint": "Höher = strenger, nur rein leere Seiten. Niedriger = erlaubt Seiten mit etwas Inhalt."
}, },
"imageToPdf": { "imageToPdf": {
"name": "Bilder zu PDF", "name": "Bilder zu PDF",

View File

@@ -163,7 +163,8 @@
}, },
"removeBlankPages": { "removeBlankPages": {
"name": "Remove Blank Pages", "name": "Remove Blank Pages",
"subtitle": "Automatically detect and delete blank pages." "subtitle": "Automatically detect and delete blank pages.",
"sensitivityHint": "Higher = stricter, only purely blank pages. Lower = allows pages with some content."
}, },
"imageToPdf": { "imageToPdf": {
"name": "Images to PDF", "name": "Images to PDF",

View File

@@ -163,7 +163,8 @@
}, },
"removeBlankPages": { "removeBlankPages": {
"name": "Eliminar Páginas en Blanco", "name": "Eliminar Páginas en Blanco",
"subtitle": "Detecta y elimina automáticamente páginas en blanco." "subtitle": "Detecta y elimina automáticamente páginas en blanco.",
"sensitivityHint": "Mayor = más estricto, solo páginas completamente en blanco. Menor = permite páginas con algo de contenido."
}, },
"imageToPdf": { "imageToPdf": {
"name": "Imágenes a PDF", "name": "Imágenes a PDF",

View File

@@ -163,7 +163,8 @@
}, },
"removeBlankPages": { "removeBlankPages": {
"name": "Supprimer les pages blanches", "name": "Supprimer les pages blanches",
"subtitle": "Détecter et supprimer automatiquement les pages vides." "subtitle": "Détecter et supprimer automatiquement les pages vides.",
"sensitivityHint": "Plus élevé = plus strict, uniquement les pages vierges. Plus bas = autorise les pages avec du contenu."
}, },
"imageToPdf": { "imageToPdf": {
"name": "Images vers PDF", "name": "Images vers PDF",

View File

@@ -163,7 +163,8 @@
}, },
"removeBlankPages": { "removeBlankPages": {
"name": "Hapus Halaman Kosong", "name": "Hapus Halaman Kosong",
"subtitle": "Deteksi dan hapus halaman kosong secara otomatis." "subtitle": "Deteksi dan hapus halaman kosong secara otomatis.",
"sensitivityHint": "Lebih tinggi = lebih ketat, hanya halaman yang benar-benar kosong. Lebih rendah = mengizinkan halaman dengan sedikit konten."
}, },
"imageToPdf": { "imageToPdf": {
"name": "Gambar ke PDF", "name": "Gambar ke PDF",

View File

@@ -163,7 +163,8 @@
}, },
"removeBlankPages": { "removeBlankPages": {
"name": "Rimuovi Pagine Vuote", "name": "Rimuovi Pagine Vuote",
"subtitle": "Rileva e elimina automaticamente le pagine vuote." "subtitle": "Rileva e elimina automaticamente le pagine vuote.",
"sensitivityHint": "Più alto = più rigoroso, solo pagine completamente vuote. Più basso = consente pagine con qualche contenuto."
}, },
"imageToPdf": { "imageToPdf": {
"name": "Immagini in PDF", "name": "Immagini in PDF",

View File

@@ -163,7 +163,8 @@
}, },
"removeBlankPages": { "removeBlankPages": {
"name": "Blanco pagina's Verwijderen", "name": "Blanco pagina's Verwijderen",
"subtitle": "Automatisch blanco pagina's detecteren en verwijderen." "subtitle": "Automatisch blanco pagina's detecteren en verwijderen.",
"sensitivityHint": "Hoger = strenger, alleen volledig lege pagina's. Lager = staat pagina's met enige inhoud toe."
}, },
"imageToPdf": { "imageToPdf": {
"name": "Afbeelding naar PDF", "name": "Afbeelding naar PDF",

View File

@@ -163,7 +163,8 @@
}, },
"removeBlankPages": { "removeBlankPages": {
"name": "Remover Páginas em Branco", "name": "Remover Páginas em Branco",
"subtitle": "Detecte e exclua automaticamente páginas em branco." "subtitle": "Detecte e exclua automaticamente páginas em branco.",
"sensitivityHint": "Maior = mais rigoroso, apenas páginas totalmente em branco. Menor = permite páginas com algum conteúdo."
}, },
"imageToPdf": { "imageToPdf": {
"name": "Imagem para PDF", "name": "Imagem para PDF",

View File

@@ -163,7 +163,8 @@
}, },
"removeBlankPages": { "removeBlankPages": {
"name": "Ta bort tomma sidor", "name": "Ta bort tomma sidor",
"subtitle": "Automatiskt identifiera och ta bort tomma sidor." "subtitle": "Automatiskt identifiera och ta bort tomma sidor.",
"sensitivityHint": "Högre = striktare, bara helt tomma sidor. Lägre = tillåter sidor med visst innehåll."
}, },
"imageToPdf": { "imageToPdf": {
"name": "Bilder till PDF", "name": "Bilder till PDF",

View File

@@ -163,7 +163,8 @@
}, },
"removeBlankPages": { "removeBlankPages": {
"name": "Boş Sayfaları Kaldır", "name": "Boş Sayfaları Kaldır",
"subtitle": "Boş sayfaları otomatik olarak tespit edin ve silin." "subtitle": "Boş sayfaları otomatik olarak tespit edin ve silin.",
"sensitivityHint": "Yüksek = daha katı, yalnızca tamamen boş sayfalar. Düşük = biraz içerik olan sayfalara izin verir."
}, },
"imageToPdf": { "imageToPdf": {
"name": "Görselden PDF'ye", "name": "Görselden PDF'ye",

View File

@@ -163,7 +163,8 @@
}, },
"removeBlankPages": { "removeBlankPages": {
"name": "Xóa trang trống", "name": "Xóa trang trống",
"subtitle": "Tự động phát hiện và xóa trang trống." "subtitle": "Tự động phát hiện và xóa trang trống.",
"sensitivityHint": "Cao hơn = nghiêm ngặt hơn, chỉ các trang hoàn toàn trống. Thấp hơn = cho phép trang có một số nội dung."
}, },
"imageToPdf": { "imageToPdf": {
"name": "Hình ảnh sang PDF", "name": "Hình ảnh sang PDF",

View File

@@ -163,7 +163,8 @@
}, },
"removeBlankPages": { "removeBlankPages": {
"name": "移除空白頁面", "name": "移除空白頁面",
"subtitle": "自動偵測並刪除空白頁面。" "subtitle": "自動偵測並刪除空白頁面。",
"sensitivityHint": "越高 = 越嚴格,僅偵測純空白頁面。越低 = 允許包含少量內容的頁面。"
}, },
"imageToPdf": { "imageToPdf": {
"name": "圖片轉 PDF", "name": "圖片轉 PDF",

View File

@@ -163,7 +163,8 @@
}, },
"removeBlankPages": { "removeBlankPages": {
"name": "移除空白页", "name": "移除空白页",
"subtitle": "自动检测并删除空白页。" "subtitle": "自动检测并删除空白页。",
"sensitivityHint": "越高 = 越严格,仅检测纯空白页。越低 = 允许包含少量内容的页面。"
}, },
"imageToPdf": { "imageToPdf": {
"name": "图片转 PDF", "name": "图片转 PDF",

View File

@@ -2,7 +2,10 @@ import { PDFDocument } from 'pdf-lib';
import * as pdfjsLib from 'pdfjs-dist'; import * as pdfjsLib from 'pdfjs-dist';
import { createIcons, icons } from 'lucide'; import { createIcons, icons } from 'lucide';
pdfjsLib.GlobalWorkerOptions.workerSrc = new URL('pdfjs-dist/build/pdf.worker.min.mjs', import.meta.url).toString(); pdfjsLib.GlobalWorkerOptions.workerSrc = new URL(
'pdfjs-dist/build/pdf.worker.min.mjs',
import.meta.url
).toString();
// State // State
const pageState: { const pageState: {
@@ -14,7 +17,7 @@ const pageState: {
pdfDoc: null, pdfDoc: null,
file: null, file: null,
detectedBlankPages: [], detectedBlankPages: [],
pageThumbnails: new Map() pageThumbnails: new Map(),
}; };
function showLoader(msg = 'Processing...') { function showLoader(msg = 'Processing...') {
@@ -23,9 +26,16 @@ function showLoader(msg = 'Processing...') {
if (txt) txt.textContent = msg; if (txt) txt.textContent = msg;
} }
function hideLoader() { document.getElementById('loader-modal')?.classList.add('hidden'); } function hideLoader() {
document.getElementById('loader-modal')?.classList.add('hidden');
}
function showAlert(title: string, msg: string, type = 'error', cb?: () => void) { function showAlert(
title: string,
msg: string,
type = 'error',
cb?: () => void
) {
const modal = document.getElementById('alert-modal'); const modal = document.getElementById('alert-modal');
const t = document.getElementById('alert-title'); const t = document.getElementById('alert-title');
const m = document.getElementById('alert-message'); const m = document.getElementById('alert-message');
@@ -46,7 +56,9 @@ function showAlert(title: string, msg: string, type = 'error', cb?: () => void)
function downloadFile(blob: Blob, filename: string) { function downloadFile(blob: Blob, filename: string) {
const url = URL.createObjectURL(blob); const url = URL.createObjectURL(blob);
const a = document.createElement('a'); const a = document.createElement('a');
a.href = url; a.download = filename; a.click(); a.href = url;
a.download = filename;
a.click();
URL.revokeObjectURL(url); URL.revokeObjectURL(url);
} }
@@ -54,7 +66,8 @@ function updateFileDisplay() {
const area = document.getElementById('file-display-area'); const area = document.getElementById('file-display-area');
if (!area || !pageState.file || !pageState.pdfDoc) return; if (!area || !pageState.file || !pageState.pdfDoc) return;
const fileSize = pageState.file.size < 1024 * 1024 const fileSize =
pageState.file.size < 1024 * 1024
? `${(pageState.file.size / 1024).toFixed(1)} KB` ? `${(pageState.file.size / 1024).toFixed(1)} KB`
: `${(pageState.file.size / 1024 / 1024).toFixed(2)} MB`; : `${(pageState.file.size / 1024 / 1024).toFixed(2)} MB`;
const pageCount = pageState.pdfDoc.getPageCount(); const pageCount = pageState.pdfDoc.getPageCount();
@@ -80,7 +93,7 @@ function resetState() {
pageState.pdfDoc = null; pageState.pdfDoc = null;
pageState.file = null; pageState.file = null;
pageState.detectedBlankPages = []; pageState.detectedBlankPages = [];
pageState.pageThumbnails.forEach(url => URL.revokeObjectURL(url)); pageState.pageThumbnails.forEach((url) => URL.revokeObjectURL(url));
pageState.pageThumbnails.clear(); pageState.pageThumbnails.clear();
const area = document.getElementById('file-display-area'); const area = document.getElementById('file-display-area');
@@ -89,6 +102,12 @@ function resetState() {
document.getElementById('preview-panel')?.classList.add('hidden'); document.getElementById('preview-panel')?.classList.add('hidden');
const inp = document.getElementById('file-input') as HTMLInputElement; const inp = document.getElementById('file-input') as HTMLInputElement;
if (inp) inp.value = ''; if (inp) inp.value = '';
const slider = document.getElementById(
'sensitivity-slider'
) as HTMLInputElement;
if (slider) slider.value = '80';
const sliderLabel = document.getElementById('sensitivity-value');
if (sliderLabel) sliderLabel.textContent = '80';
} }
async function handleFileUpload(file: File) { async function handleFileUpload(file: File) {
@@ -113,8 +132,11 @@ async function handleFileUpload(file: File) {
} }
} }
async function isPageBlank(page: any, threshold = 250): Promise<boolean> { async function isPageBlank(
const viewport = page.getViewport({ scale: 0.5 }); // Lower scale for faster processing page: any,
maxNonWhitePercent = 0.5
): Promise<boolean> {
const viewport = page.getViewport({ scale: 0.5 });
const canvas = document.createElement('canvas'); const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d'); const ctx = canvas.getContext('2d');
if (!ctx) return false; if (!ctx) return false;
@@ -126,19 +148,20 @@ async function isPageBlank(page: any, threshold = 250): Promise<boolean> {
const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height); const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
const data = imageData.data; const data = imageData.data;
const totalPixels = data.length / 4;
let totalBrightness = 0; let nonWhitePixels = 0;
for (let i = 0; i < data.length; i += 4) { for (let i = 0; i < data.length; i += 4) {
const r = data[i], g = data[i + 1], b = data[i + 2]; const brightness = (data[i] + data[i + 1] + data[i + 2]) / 3;
totalBrightness += (r + g + b) / 3; if (brightness < 240) nonWhitePixels++;
} }
const avgBrightness = totalBrightness / (data.length / 4); const nonWhitePercent = (nonWhitePixels / totalPixels) * 100;
return avgBrightness > threshold; return nonWhitePercent <= maxNonWhitePercent;
} }
async function generateThumbnail(page: any): Promise<string> { async function generateThumbnail(page: any): Promise<string> {
const viewport = page.getViewport({ scale: 0.3 }); const viewport = page.getViewport({ scale: 1.5 });
const canvas = document.createElement('canvas'); const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d'); const ctx = canvas.getContext('2d');
if (!ctx) return ''; if (!ctx) return '';
@@ -151,11 +174,14 @@ async function generateThumbnail(page: any): Promise<string> {
} }
async function detectBlankPages() { async function detectBlankPages() {
if (!pageState.pdfDoc || !pageState.file) return showAlert('Error', 'Please upload a PDF first.'); if (!pageState.pdfDoc || !pageState.file)
return showAlert('Error', 'Please upload a PDF first.');
const sensitivitySlider = document.getElementById('sensitivity-slider') as HTMLInputElement; const sensitivitySlider = document.getElementById(
'sensitivity-slider'
) as HTMLInputElement;
const sensitivityPercent = parseInt(sensitivitySlider?.value || '80'); const sensitivityPercent = parseInt(sensitivitySlider?.value || '80');
const threshold = Math.round(255 - (sensitivityPercent * 2.55)); const maxNonWhitePercent = 5 - (sensitivityPercent / 100) * 4.9;
showLoader('Detecting blank pages...'); showLoader('Detecting blank pages...');
try { try {
@@ -164,12 +190,12 @@ async function detectBlankPages() {
const totalPages = pdfDoc.numPages; const totalPages = pdfDoc.numPages;
pageState.detectedBlankPages = []; pageState.detectedBlankPages = [];
pageState.pageThumbnails.forEach(url => URL.revokeObjectURL(url)); pageState.pageThumbnails.forEach((url) => URL.revokeObjectURL(url));
pageState.pageThumbnails.clear(); pageState.pageThumbnails.clear();
for (let i = 1; i <= totalPages; i++) { for (let i = 1; i <= totalPages; i++) {
const page = await pdfDoc.getPage(i); const page = await pdfDoc.getPage(i);
if (await isPageBlank(page, threshold)) { if (await isPageBlank(page, maxNonWhitePercent)) {
pageState.detectedBlankPages.push(i - 1); // 0-indexed pageState.detectedBlankPages.push(i - 1); // 0-indexed
const thumbnail = await generateThumbnail(page); const thumbnail = await generateThumbnail(page);
pageState.pageThumbnails.set(i - 1, thumbnail); pageState.pageThumbnails.set(i - 1, thumbnail);
@@ -247,12 +273,13 @@ function togglePageSelection(div: HTMLElement, pageIndex: number) {
} }
async function processRemoveBlankPages() { async function processRemoveBlankPages() {
if (!pageState.pdfDoc || !pageState.file) return showAlert('Error', 'Please upload a PDF first.'); if (!pageState.pdfDoc || !pageState.file)
return showAlert('Error', 'Please upload a PDF first.');
// Get selected pages to remove // Get selected pages to remove
const previewContainer = document.getElementById('blank-pages-preview'); const previewContainer = document.getElementById('blank-pages-preview');
const selectedPages: number[] = []; const selectedPages: number[] = [];
previewContainer?.querySelectorAll('[data-selected="true"]').forEach(el => { previewContainer?.querySelectorAll('[data-selected="true"]').forEach((el) => {
const pageIndex = parseInt((el as HTMLElement).dataset.pageIndex || '-1'); const pageIndex = parseInt((el as HTMLElement).dataset.pageIndex || '-1');
if (pageIndex >= 0) selectedPages.push(pageIndex); if (pageIndex >= 0) selectedPages.push(pageIndex);
}); });
@@ -275,8 +302,16 @@ async function processRemoveBlankPages() {
} }
const newPdfBytes = await newPdf.save(); const newPdfBytes = await newPdf.save();
downloadFile(new Blob([new Uint8Array(newPdfBytes)], { type: 'application/pdf' }), 'blank-pages-removed.pdf'); downloadFile(
showAlert('Success', `Removed ${selectedPages.length} blank page(s) successfully!`, 'success', resetState); new Blob([new Uint8Array(newPdfBytes)], { type: 'application/pdf' }),
'blank-pages-removed.pdf'
);
showAlert(
'Success',
`Removed ${selectedPages.length} blank page(s) successfully!`,
'success',
resetState
);
} catch (e) { } catch (e) {
console.error(e); console.error(e);
showAlert('Error', 'Could not remove blank pages.'); showAlert('Error', 'Could not remove blank pages.');
@@ -290,7 +325,9 @@ document.addEventListener('DOMContentLoaded', () => {
const dropZone = document.getElementById('drop-zone'); const dropZone = document.getElementById('drop-zone');
const detectBtn = document.getElementById('detect-btn'); const detectBtn = document.getElementById('detect-btn');
const processBtn = document.getElementById('process-btn'); const processBtn = document.getElementById('process-btn');
const sensitivitySlider = document.getElementById('sensitivity-slider') as HTMLInputElement; const sensitivitySlider = document.getElementById(
'sensitivity-slider'
) as HTMLInputElement;
const sensitivityValue = document.getElementById('sensitivity-value'); const sensitivityValue = document.getElementById('sensitivity-value');
sensitivitySlider?.addEventListener('input', (e) => { sensitivitySlider?.addEventListener('input', (e) => {

View File

@@ -23,7 +23,7 @@ export class RemoveBlankPagesNode extends BaseWorkflowNode {
private async isPageBlank( private async isPageBlank(
page: pdfjsLib.PDFPageProxy, page: pdfjsLib.PDFPageProxy,
threshold: number maxNonWhitePercent: number
): Promise<boolean> { ): Promise<boolean> {
const viewport = page.getViewport({ scale: 0.5 }); const viewport = page.getViewport({ scale: 0.5 });
const canvas = document.createElement('canvas'); const canvas = document.createElement('canvas');
@@ -34,12 +34,14 @@ export class RemoveBlankPagesNode extends BaseWorkflowNode {
const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height); const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
const data = imageData.data; const data = imageData.data;
let totalBrightness = 0; const totalPixels = data.length / 4;
let nonWhitePixels = 0;
for (let i = 0; i < data.length; i += 4) { for (let i = 0; i < data.length; i += 4) {
totalBrightness += (data[i] + data[i + 1] + data[i + 2]) / 3; const brightness = (data[i] + data[i + 1] + data[i + 2]) / 3;
if (brightness < 240) nonWhitePixels++;
} }
const avgBrightness = totalBrightness / (data.length / 4); const nonWhitePercent = (nonWhitePixels / totalPixels) * 100;
return avgBrightness > threshold; return nonWhitePercent <= maxNonWhitePercent;
} }
async data( async data(
@@ -50,7 +52,10 @@ export class RemoveBlankPagesNode extends BaseWorkflowNode {
const threshCtrl = this.controls['threshold'] as const threshCtrl = this.controls['threshold'] as
| ClassicPreset.InputControl<'number'> | ClassicPreset.InputControl<'number'>
| undefined; | undefined;
const threshold = Math.max(200, Math.min(255, threshCtrl?.value ?? 250)); const maxNonWhitePercent = Math.max(
0.1,
Math.min(5, threshCtrl?.value ?? 0.5)
);
return { return {
pdf: await processBatch(pdfInputs, async (input) => { pdf: await processBatch(pdfInputs, async (input) => {
@@ -61,7 +66,7 @@ export class RemoveBlankPagesNode extends BaseWorkflowNode {
for (let i = 1; i <= pdfjsDoc.numPages; i++) { for (let i = 1; i <= pdfjsDoc.numPages; i++) {
const page = await pdfjsDoc.getPage(i); const page = await pdfjsDoc.getPage(i);
const blank = await this.isPageBlank(page, threshold); const blank = await this.isPageBlank(page, maxNonWhitePercent);
if (!blank) { if (!blank) {
nonBlankIndices.push(i - 1); nonBlankIndices.push(i - 1);
} else { } else {

View File

@@ -193,8 +193,12 @@
step="5" step="5"
class="w-full h-2 bg-gray-700 rounded-lg appearance-none cursor-pointer" class="w-full h-2 bg-gray-700 rounded-lg appearance-none cursor-pointer"
/> />
<p class="text-xs text-gray-400 mt-1"> <p
Higher values detect more pages as blank class="text-xs text-gray-400 mt-1"
data-i18n="tools:removeBlankPages.sensitivityHint"
>
Higher = stricter, only purely blank pages. Lower = allows pages
with some content.
</p> </p>
</div> </div>
<button id="detect-btn" class="btn-gradient w-full mt-4"> <button id="detect-btn" class="btn-gradient w-full mt-4">
@@ -210,7 +214,7 @@
<p id="preview-info" class="text-gray-400 text-sm mb-4"></p> <p id="preview-info" class="text-gray-400 text-sm mb-4"></p>
<div <div
id="blank-pages-preview" id="blank-pages-preview"
class="grid grid-cols-3 md:grid-cols-4 gap-3 max-h-64 overflow-y-auto p-2 bg-gray-900 rounded-lg border border-gray-700" class="grid grid-cols-3 md:grid-cols-4 gap-3 p-2 bg-gray-900 rounded-lg border border-gray-700"
></div> ></div>
<button id="process-btn" class="btn-gradient w-full mt-4"> <button id="process-btn" class="btn-gradient w-full mt-4">
Remove Selected Blank Pages Remove Selected Blank Pages