← 返回蜂巢洞察

如何使用JavaScript构建一个基于浏览器的PDF转灰度图像的工具

许多PDF文档中包含色彩丰富的图表、演示文稿、营销材料、扫描页或图形,而这些内容并不总是适合用于打印或归档。在某些情况下,将文档转换为灰度格式可以减少视觉干扰,生成更适合打印的文件,降低打印成本,或者为黑白出版做好准备。PDF转灰度转换工具能够自动化这一过程:用户无需手动编辑每一页,只需在浏览器中上传PDF文件,选择灰度转换的方式,预览结果,然后下载新生成的文件即可。 在本教程中,您将使用JavaScript开发一个基于浏览器的PDF转灰度转换工具。用户可以通过该工具上传PDF文件,预览每一页的内容,调整灰度程度,在多种转换模式中进行选择,指定需要处理的页面,生成灰度版本的PDF文件,预览最终

许多PDF文档中包含色彩丰富的图表、演示文稿、营销材料、扫描页或图形,而这些内容并不总是适合用于打印或归档。在某些情况下,将文档转换为灰度格式可以减少视觉干扰,生成更适合打印的文件,降低打印成本,或者为黑白出版做好准备。PDF转灰度转换工具能够自动化这一过程:用户无需手动编辑每一页,只需在浏览器中上传PDF文件,选择灰度转换的方式,预览结果,然后下载新生成的文件即可。 在本教程中,您将使用JavaScript开发一个基于浏览器的PDF转灰度转换工具。用户可以通过该工具上传PDF文件,预览每一页的内容,调整灰度程度,在多种转换模式中进行选择,指定需要处理的页面,生成灰度版本的PDF文件,预览最终结果,重命名输出文件,并直接下载它,而无需将文档上传到外部服务器。 我们将使用PDF.js来渲染PDF页面,利用HTML Canvas API来操作图像像素,同时借助PDF-lib来生成最终的可供下载的PDF文件。完成本教程的学习后,您将掌握一个类似于All In One Tools中提供的、功能完备的客户端PDF处理工具。

目录

这个PDF转灰度转换工具的功能及工作原理

PDF转灰度转换工具会将彩色PDF页面转换为灰度版本,同时保留文档的布局、页面尺寸、文本位置以及图片内容。该工具并不会删除任何内容,而是重新计算每个像素的颜色,从而使整个页面呈现为灰度效果。

这种方法有助于生成适合打印的文档,减少颜色带来的干扰,为单色打印准备文件,提高扫描文档的一致性,或者制作黑白版本以供审核或归档使用。

在这个项目中,用户可以上传PDF文件,浏览每一页,调整灰度强度,在不同的转换模式中选择,决定是转换所有页面还是仅转换选中的页面,生成新的灰度PDF文件,预览完成后的文档,重命名输出文件,并直接通过浏览器下载它。

在后台,PDF.js会将每一页PDF内容渲染到HTML画布上。一旦页面被渲染出来,JavaScript就会读取每个像素的RGB值,然后利用亮度公式计算出对应的灰度值。这些更新后的像素会被重新写入画布中,之后PDF-lib会将所有处理过的页面合并成一个新的PDF文件。

一个典型的像素包含四个数值:

const pixel = {
    red: 180,
    green: 95,
    blue: 40,
    alpha: 255
};

要将这个像素转换为灰度,JavaScript会计算出一个亮度值,并将其均匀地应用到红色、绿色和蓝色通道中。

const gray = 0.299 * red + 0.587 * green + 0.114 * blue;

这样处理后,这个像素就会变成灰度值:

pixel.red = gray;
pixel.green = gray;
pixel.blue = gray;

对每一份选中文档中的每个像素都重复这一过程,就能得到原始PDF文件的灰度版本,同时文档的整体结构也会保持不变。

项目设置

在编写转换逻辑之前,我们先来创建一个简单的项目结构吧。

我们将使用HTML、CSS和JavaScript,再加上PDF.js、Canvas API以及PDF-lib来实现这个项目。

我们的项目结构如下所示:

pdf-to-grayscale/
│── index.html
│── style.css
│── script.js
│── pdf.worker.min.js
│── assets/

将HTML、样式代码和JavaScript分开存放,可以让项目在后续添加更多功能时更容易维护。

所使用的库

“PDF转灰度”转换工具依赖于三项浏览器技术,这些技术共同协作,用于渲染PDF页面、处理图像像素,并生成新的可下载文档。

PDF.js能够在浏览器内部直接渲染PDF页面。

HTML Canvas API提供了对每个像素的访问权限,这样JavaScript就能将颜色转换为灰度值。

PDF-lib在所有选中的页面都被处理完成后,会生成最终的PDF文件。

在加载应用程序之前,请先引入所需的库文件。

<script src="https://cdnjs.cloudflare.com/ajax/libs/pdf.js/4.4.168/pdf.min.js"></script>
<script src="https://unpkg.com/pdf-lib/dist/pdf-lib.min.js"></script>
<script src="script.js"></script>

配置PDF.js工作线程。

pdfjsLib.GlobalWorkerOptions.workerSrc = "pdf.worker.min.js";

使用工作线程可以让PDF渲染在后台进行,而不会导致浏览器界面冻结。

创建HTML布局

该应用程序分为四个主要部分:

  • 上传区域

  • PDF预览区

  • 转换设置选项

  • 下载区域

首先创建基本的页面结构。

<section id="uploadSection"></section>
<section id="previewSection" hidden></section>
<section id="settingsSection" hidden></section>
<section id="downloadSection" hidden></section>

页面首次加载时,只有上传区域是可见的。只有在成功打开PDF文件后,其他部分才会显示出来。

选择主要元素

保存那些将在整个应用程序中被使用的元素的引用。

const uploadSection = document.getElementById("uploadSection");
const previewSection = document.getElementById("previewSection");
const settingsSection = document.getElementById("settingsSection");
const pdfCanvas = document.getElementById("pdfCanvas");

使用这些引用可以在用户进行转换操作时更方便地更新界面内容。

上传和预览PDF文件

上传区域支持拖放操作,也允许用户手动选择文件。

当选中某个文件后,首先要验证它是否为PDF格式。

async function uploadPdf(file) {
    if (!file || file.type !== "application/pdf") {
        alert("请选择一个PDF文件。");
        return;
    }

    await loadPdf(file);
}

验证通过后,该文件会被加载到内存中以便进行后续处理。

用于选择PDF文件的上传区域。

加载PDF文件

在用PDF.js打开文件之前,需要先将上传的文件转换为ArrayBuffer格式。

async function loadPdf(file) {
    const bytes = await file.arrayBuffer();

    pdfDocument = await pdfjsLib.getDocument({
        data: bytes
    }).promise;

    currentPage = 1;
    renderPage(currentPage);
}

加载后的PDF文件会被保存下来,这样以后就可以将其中的每一页都转换为灰度图像了。

渲染PDF页面

PDF.js会一次在HTML画布上渲染一页内容。

首先需要获取相应的页面数据。

const page = await pdfDocument getPage(currentPage);

创建视图窗口。

const viewport = page.getViewport({
    scale: 1.5
});

调整画布的大小。

pdfCanvas.width = viewport.width;
pdfCanvas.height = viewport.height;

渲染页面内容。

await page.render({
    canvasContext: pdfCanvas.getContext("2d"),
    viewport
}).promise;

一旦渲染完成,所选页面就会显示在预览区域中。

使用PDF.js渲染的PDF页面预览图。

在页面之间切换

大多数PDF文档都包含多页内容,因此用户需要简单的导航工具。

记录当前所在的页面。

let currentPage = 1;
let pdfDocument = null;

跳转到上一页。

previousButton.addEventListener("click", async () => {
    if (currentPage > 1) {
        currentPage--;
        await renderPage(currentPage);
    }
});

跳转到下一页。

nextButton.addEventListener("click", async () => {
    if (currentPage < pdfDocument.numPages) {
        currentPage++;
        await renderPage(currentPage);
    }
});

更新页面显示信息。

pageCounter.textContent = `当前页码:${currentPage},总页数:${pdfDocument.numPages}`;

现在用户可以在决定如何进行灰度转换之前,先浏览整个文档内容。

设置转换参数

在PDF文件被加载并完成预览后,用户可以配置该文件应如何转换为灰度格式。设置面板允许用户调整灰度强度、选择转换模式、指定需要处理的页面范围,然后开始转换过程。

PDF转灰度转换工具的设置界面,包含灰度强度滑块、转换模式选项及页面筛选功能。

调整灰度强度

灰度强度滑块用于控制灰度效果的强弱程度。

较低的数值会保留更多的原始颜色信息,而较高的数值则能生成真正的灰度效果。

创建这个滑块控件。

<input type="range" id="grayIntensity" min="0" max="100" value="100">

读取用户选择的数值值。

const intensity = Number(document.getElementById("grayIntensity").value);

所选择的灰度级别将在后续计算最终灰度颜色时被使用。

选择转换模式

该工具提供了多种适用于不同场景的灰度处理模式。

创建用于选择模式的单选按钮。

<input type="radio" name="mode" value="standard" checked>
标准灰度模式
<input type="radio" name="mode" value="threshold">
黑白模式
<input type="radio" name="mode" value="soft">
柔和灰度模式

获取用户选择的转换模式。

const conversionMode = document.querySelector(
    'input[name="mode"]:checked'
).value;

每种模式在处理画布像素时都会使用不同的算法。

选择要转换的页面

用户可以选择转换整个文档,也可以仅转换选中的部分页面。

创建用于选择页面的控制元素。

<input type="radio" name="pages" value="all" checked>
所有页面
<input type="radio" name="pages" value="custom">
特定页面
<input type="text" id="pageRange" placeholder="例如:1、3-5、10">

读取用户选择的页面范围。

const applyMode = document.querySelector(
    'input[name="pages"]:checked'
).value;

如果选择了“所有页面”,则PDF中的所有页面都会被转换;否则,只有用户指定的页面才会被处理。

将PDF页面转换为灰度图像

设置完成后,用户就可以开始进行转换了。

创建用于启动转换的操作按钮。

<button id="convertPdf">>转换为灰度图像</button>

启动转换过程。

convertButton.addEventListener("click", async () => {
    await convertPdf();
});
转换按钮位于设置选项下方,高度为400像素,加载方式为延迟加载,图片地址为:https://cdn.hashnode.com/uploads/covers/6979d22f93bc273cc33971b1/baede49d-a7e5-4ca5-9322-4b041bb6bfb4.png,显示方式为块级布局,内外边距均为0,宽度为600像素。

重新开始

用户可以清除当前文档的内容,使应用程序恢复到初始状态。

创建用于重置的按钮。

<button id="resetTool">>重新开始

重置应用程序的状态。

resetTool.addEventListener("click", () => {
    location.reload();
});

这样做会删除当前的PDF文件,并恢复默认设置,从而允许用户继续处理其他文档。

读取画布像素数据

当页面被渲染完成后,可以获取其像素数据。

const imageData = context.getImageData(
    0,
    0,
    canvas.width,
    canvas.height
);

这些像素信息会被存储在一个数组中。

const pixels = imageData.data;

每个像素包含四个数值:

  • 红色

  • 绿色

  • 蓝色

  • 透明度

我们会修改RGB值,但保持透明度通道不变。

将颜色转换为灰度

标准的灰度转换算法会利用红色、绿色和蓝色通道来计算亮度值。

需要遍历所有的像素。

for (let i = 0; i < pixels.length; i += 4) {
    const gray =
        0.299 * pixels[i] +
        0.587 * pixels[i + 1] +
        0.114 * pixels[i + 2];

    pixels[i] = gray;
    pixels[i + 1] = gray;
    pixels[i + 2] = gray;
}

这种计算方法能够生成看起来非常自然的灰度图像,因为它符合人眼对亮度的感知方式。

应用所选的转换模式

不同的转换模式会使用不同的算法来处理像素数据。

例如,黑白(阈值)模式会将每个像素转换为纯黑色或纯白色。

const threshold = 128;
const color = gray >= threshold ? 255 : 0;
pixels[i] = color;
pixels[i + 1] = color;
pixels[i + 2] = color;

柔和灰度模式则会将原始颜色与灰度值混合,从而产生更为柔和的效果。

const softGray =
    (gray * 0.6) +
    (pixels[i] * 0.4);

pixels[i] = softGray;
pixels[i + 1] = softGray;
pixels[i + 2] = softGray;

一旦选择了某种转换模式,就需要将处理后的像素数据写回画布中。

context.putImageData(
    imageData,
    0,
    0
);
应用灰度转换后的PDF页面预览图

处理选定的页面

每次不需要处理整个文档,只需转换用户选中的那些页面即可。

需要遍历指定的页面范围。

for (let page = startPage; page <= endPage; page++) {
    await processPage(page);
}

每处理完一个页面,这些数据都会被暂时存储起来,直到最终生成PDF文件。

生成最终的PDF文件

创建一个新的PDF文档。

const outputPdf = await PDFLib.PDFDocument.create();

将处理后的图像转换为字节格式。

const imageBytes = await canvasToBytes(pdfCanvas);

将生成的图像嵌入到PDF文档中。

const image = await outputPdf.embedPng(imageBytes);

创建一个新的页面。

const page = outputPdf.addPage([
    image.width,
    image.height
]);

在新的页面上绘制处理后的图像。

page.drawImage(image, {
    x: 0,
    y: 0,
    width: image.width,
    height: image.height
});

对每一个选中的页面重复上述步骤,直到新的灰度PDF文档制作完成。

保存生成的PDF文件

所有页面处理完成后,将完成的PDF文档保存下来。

const pdfBytes = await outputPdf.save();

创建一个可供下载的PDF文件。

generatedPdfBlob = new Blob([pdfBytes], {
    type: "application/pdf"
});

现在,这个灰度PDF文件已经可以用来预览、重命名或下载了。

预览结果

在下载转换后的PDF文件之前,让用户先查看最终效果是非常有用的。这样他们就可以确认选中的页面是否已经被正确转换,以及灰度效果是否符合他们的预期。

使用PDF.js来加载生成的PDF文件。

let finalPdf = null;

async function showResult() {
    const bytes = await generatedPdfBlob.arrayBuffer();

    finalPdf = await pdfjsLib.getDocument({
        data: bytes
    }).promise;

    renderResultPage(1);
}

渲染选中的页面。

async function renderResultPage(pageNumber) {
    const page = await finalPdf.getPage(pageNumber);

    const viewport = page.getViewport({
        scale: 1.5
    });

    resultCanvas.width = viewport.width;
    resultCanvas.height = viewport.height;

    await page.render({
        canvasContext: resultCanvas.getContext("2d"),
        viewport
    }).promise;
}

用户可以在下载PDF文件之前浏览所有已转换的页面。

重命名与下载

在保存转换后的PDF文件之前,用户可以为其指定一个自定义的文件名。

创建用于输入文件名的元素。

<input
    type="text"
    id="outputFilename"
    value="grayscale-document.pdf"
>

获取用户输入的文件名。

function getFilename() {
    let filename = outputFilename.value.trim();

    if (!filename) {
        filename = "grayscale-document.pdf";
    }

    if (!filename.toLowerCase().endsWith(".pdf")) {
        filename += ".pdf";
    }

    return filename;
}

显示有关生成的PDF的信息。

pageCount.textContent = `${finalPdf.numPages} 页`;
fileSize.textContent = formatFileSize(generatedPdfBlob.size);

下载完成的PDF文件。

downloadButton.addEventListener("click", () => {
    const url = URL.createObjectURL(generated PdfBlob);

    const link = document.createElement("a");
    link.href = url;
    link.download = getFilename();
    link.click();

    URL.revokeObjectURL(url);
});

所有操作都在浏览器内部完成,因此用户在整个转换过程中可以保证他们的文件隐私得到保护。

下载页面,会显示输出文件的名称、页数、文件大小以及下载按钮。

演示:PDF转灰度转换器的使用方法

让我们一起来了解整个转换流程。

步骤1:上传PDF文件

用户只需将PDF文件拖放到上传区域,或点击选择PDF文件即可。

用于选择PDF文件的上传区域。

步骤2:预览文档

PDF.js会逐页显示上传的文档,让用户能够在转换之前先查看文件内容。

待转换的PDF文件。

步骤3:配置转换参数

用户可以调整灰度等级,选择转换模式,并决定是转换所有页面还是仅转换选中的页面。

灰度转换设置面板。

步骤4:转换PDF文件

点击转换为灰度格式即可开始转换选中的页面。

转换为灰度格式的按钮,还提供“重新开始”选项。

步骤5:查看转换后的文档

转换完成后,应用程序会显示生成的灰度PDF文件的预览版本。

转换后的灰度PDF预览图

步骤6:重命名并下载

最后,用户可以重新命名输出文件,查看页数和文件大小,然后下载转换后的PDF文件。

包含文件名、页数、文件大小以及下载按钮的最终下载页面

性能提示

较大的PDF文件需要更长的处理时间,因为必须渲染并转换每一页。仅处理选中的页面有助于提升处理效率。

for (let page = startPage; page <= endPage; page++) {
    await processPage(page);
}

下载文件后,应释放临时资源以减少内存占用。

URL.revokeObjectURL(downloadUrl);

这些简单的优化措施有助于确保在处理大型多页PDF文档时,转换工具仍能保持良好的响应速度。

常见错误

一个常见的错误是多次重复转换同一页面,而却没有先重新渲染原始页面。在进行任何灰度转换之前,务必先从原始PDF页面开始处理。

await renderPage(currentPage);

另一个问题在于允许用户输入无效的页码。

if (pageNumber < 1 || pageNumber > pdfDocument.numPages) {
    return;
}

最后需要记住的是,较高的输出质量通常会导致PDF文件体积增大。选择合适的质量设置有助于在图像清晰度与文件大小之间取得平衡。

总结

通过本教程,您使用JavaScript构建了一个基于浏览器的PDF转灰度转换工具。

您学会了如何上传和预览PDF文件,如何使用PDF.js渲染页面,如何利用Canvas API将彩色页面转换为灰度图像,如何处理选中的页面,如何使用PDF-lib生成新的PDF文件,如何预览完成后的文档,如何重命名输出文件,以及如何直接从浏览器中下载文件。

由于所有处理操作都是在本机进行的,因此用户可以在不将敏感文件上传到外部服务器的情况下,将PDF文件转换为灰度格式。

您可以通过PDF转灰度转换工具来体验整个处理流程。

今后,您还可以为这个项目添加更多功能,例如深褐色转换、亮度与对比度调节选项、自定义灰度预设值、批量处理PDF文件,或者支持其他图像过滤效果。

相关文章

技术实践

如何使用JavaScript开发一款基于浏览器的PDF颜色叠加工具

有时你并不想更改PDF文件的实际内容,只是想要在文档的某些部分或全部上添加一层彩色背景而已。 这种方法在制作带有品牌标识的报告、为文档添加彩色背景、突出显示打印版内容、生成设计样稿、应用水印效果,或是为演示文稿准备材料时都非常有用。 “PDF颜色覆盖工具”能够实现这一功能——它在PDF页面上叠加一层半透明的彩色层,同时保留下方的原始文本、图片和布局。 用户无需使用图形设计软件逐页进行手动编辑,只需上传PDF文件,选择所需的覆盖颜色、调整透明度、选择混合模式,指定颜色层的显示位置,预览效果后即可下载修改后的文档。 在本教程中,你将学习如何使用JavaScript来开发这个工具。用户完全可以无需将

阅读全文
技术实践

如何使用JavaScript开发一款基于浏览器的PDF模糊处理工具

许多PDF文件包含不应公开分享的信息。在将文件发送给他人之前,个人资料、财务数据、签名、地址、账号信息、员工资料或机密商业数据通常都需要被隐藏起来。 一款PDF模糊处理工具可以让这一过程变得简单。它并不会永久删除这些内容,而是会在PDF文件的指定区域添加模糊效果,这样一来,敏感信息就会变得难以阅读,而文件的其他部分则保持原样。 在这个教程中,你将使用JavaScript制作一个基于浏览器的PDF模糊处理工具。用户可以上传PDF文件,预览每一页,在敏感内容上标出需要模糊处理的区域,调整模糊程度,对选定的页面应用模糊效果,预览最终结果,然后下载处理后的PDF文件——整个过程都不需要将文件上传到服务

阅读全文
技术实践

如何使用JavaScript构建基于浏览器的PDF过滤工具开发环境

PDF编辑并不仅限于添加签名或合并文档。有时,你只是想通过增加亮度、提升对比度、添加模糊效果、将其转换为灰度图,或者应用一些创意视觉效果来改善PDF的外观——而这一切都不需要打开Photoshop或安装任何桌面软件。 在这个教程中,你将使用JavaScript、PDF.js、Canvas API以及PDF-lib构建一个基于浏览器的PDF过滤器工具。用户可以上传PDF文件,预览每一页,叠加多个过滤层,应用预设效果,处理选定的页面,预览最终结果,重新命名文件,然后直接从浏览器中下载编辑后的PDF。 由于所有操作都在用户的设备上本地进行,因此上传的PDF文件永远不会离开用户的设备,这使得这个工具既

阅读全文
技术实践

如何使用JavaScript构建基于浏览器的PDF颜色反转工具

长时间阅读PDF文档会让人感到疲劳,尤其是当文档的背景颜色很鲜艳,或者你在光线较暗的环境中阅读时。 在某些情况下,设计师、开发人员和印刷专业人士可能希望查看文档在颜色反转后的效果,或者为便于访问或审查而准备不同的版本。 PDF颜色反转工具能够实现这一目标——它在保持文档结构不变的前提下,改变PDF页面的颜色。用户无需手动编辑每一张图片或图形,只需上传PDF文件,选择颜色反转模式,指定需要处理的页面范围,调整输出质量,然后点击几下即可生成新的PDF文件并下载。 在本教程中,你将使用JavaScript制作一个基于浏览器的PDF颜色反转工具。用户可以上传PDF文件,预览其内容,选择反转方式,指定处

阅读全文