如何使用JavaScript构建一个基于浏览器的PDF转灰度图像的工具
许多PDF文档中包含色彩丰富的图表、演示文稿、营销材料、扫描页或图形,而这些内容并不总是适合用于打印或归档。在某些情况下,将文档转换为灰度格式可以减少视觉干扰,生成更适合打印的文件,降低打印成本,或者为黑白出版做好准备。PDF转灰度转换工具能够自动化这一过程:用户无需手动编辑每一页,只需在浏览器中上传PDF文件,选择灰度转换的方式,预览结果,然后下载新生成的文件即可。 在本教程中,您将使用JavaScript开发一个基于浏览器的PDF转灰度转换工具。用户可以通过该工具上传PDF文件,预览每一页的内容,调整灰度程度,在多种转换模式中进行选择,指定需要处理的页面,生成灰度版本的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.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文档都包含多页内容,因此用户需要简单的导航工具。
记录当前所在的页面。
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文件被加载并完成预览后,用户可以配置该文件应如何转换为灰度格式。设置面板允许用户调整灰度强度、选择转换模式、指定需要处理的页面范围,然后开始转换过程。
调整灰度强度
灰度强度滑块用于控制灰度效果的强弱程度。
较低的数值会保留更多的原始颜色信息,而较高的数值则能生成真正的灰度效果。
创建这个滑块控件。
<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();
});
重新开始
用户可以清除当前文档的内容,使应用程序恢复到初始状态。
创建用于重置的按钮。
<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
);
处理选定的页面
每次不需要处理整个文档,只需转换用户选中的那些页面即可。
需要遍历指定的页面范围。
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文件即可。
步骤2:预览文档
PDF.js会逐页显示上传的文档,让用户能够在转换之前先查看文件内容。
步骤3:配置转换参数
用户可以调整灰度等级,选择转换模式,并决定是转换所有页面还是仅转换选中的页面。
步骤4:转换PDF文件
点击转换为灰度格式即可开始转换选中的页面。
步骤5:查看转换后的文档
转换完成后,应用程序会显示生成的灰度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文件,预览其内容,选择反转方式,指定处
阅读全文