ASP.NET Core 使用 pdfjs 加载 实时水印 base64 编码的 PDF
先下载 pdfjs:https://github.com/mozilla/pdf.js
目前最新版本是 4.0.379
把需要的文件放到项目下面,由于最新的 pdfjs 使用的 mjs,看情况可以加下 MIME 类型:
var provider = new FileExtensionContentTypeProvider(); provider.Mappings[".mjs"] = "application/javascript"; provider.Mappings[".ftl"] = "application/x-freemarker"; app.UseStaticFiles(new StaticFileOptions { ContentTypeProvider = provider });
然后把 PDF 文件转 base64
public static string Pdf2Base64(string inputPath) { byte[] fileBytes = System.IO.File.ReadAllBytes(inputPath); return Convert.ToBase64String(fileBytes); }
我们定义个 Model ,把 PDF 的 base64 字符串传给 View
public class DefaultModel { public string PdfBase64 { get; set; } } public IActionResult Index() { DefaultModel dm=new DefaultModel(); dm.PdfBase64 = PdfHelper.Pdf2Base64("F:\\pdf\\compressed.tracemonkey-pldi-09.pdf"); return View(dm); }
然后根据示例:https://mozilla.github.io/pdf.js/examples/ ,在 View 中显示 PDF:
<script src="~/pdfjs/js/pdf.mjs" type="module"></script> <script type="module"> // atob() is used to convert base64 encoded PDF to binary-like data. // (See also https://developer.mozilla.org/en-US/docs/Web/API/WindowBase64/ // Base64_encoding_and_decoding.) var pdfData = atob('@Html.Raw(Model.PdfBase64)'); // Loaded via <script> tag, create shortcut to access PDF.js exports. var { pdfjsLib } = globalThis; // The workerSrc property shall be specified. pdfjsLib.GlobalWorkerOptions.workerSrc = '/pdfjs/js/pdf.worker.mjs'; // Using DocumentInitParameters object to load binary data. var loadingTask = pdfjsLib.getDocument({data: pdfData}); loadingTask.promise.then(function(pdf) { console.log('PDF loaded'); // Fetch the first page var pageNumber = 1; pdf.getPage(pageNumber).then(function(page) { console.log('Page loaded'); var scale = 1.5; var viewport = page.getViewport({scale: scale}); // Prepare canvas using PDF page dimensions var canvas = document.getElementById('the-canvas'); var context = canvas.getContext('2d'); canvas.height = viewport.height; canvas.width = viewport.width; // Render PDF page into canvas context var renderContext = { canvasContext: context, viewport: viewport }; var renderTask = page.render(renderContext); renderTask.promise.then(function () { console.log('Page rendered'); }); }); }, function (reason) { // PDF loading error console.error(reason); }); </script>
在页面上添加,就可以显示 pdf 了
<canvas id="the-canvas"></canvas>
不过这样我们只显示了 PDF 的第一页
对于多页 PDF ,我们还需要修改下,先加上文档的页面显示,再加上 上一页、下一页 的按钮,修改后的 HTML 如下:
<div class="text-center"> <button id="prev">上一页</button> <button id="next">下一页</button> <span>Page: <span id="page_num"></span> / <span id="page_count"></span></span> </div> <canvas id="the-canvas"></canvas> </div>
然后修改下 js 代码:
<script src="~/pdfjs/js/pdf.mjs" type="module"></script> <script type="module"> var pdfDoc = null; var pageStartNum = 1; var pageEndNum = 1; var pageNum = 1; var pdfData = safeAtob('@Html.Raw(Model.PdfBase64)'); // Loaded via <script> tag, create shortcut to access PDF.js exports. var { pdfjsLib } = globalThis; // The workerSrc property shall be specified. pdfjsLib.GlobalWorkerOptions.workerSrc = '/pdfjs/js/pdf.worker.mjs'; // Using DocumentInitParameters object to load binary data. var loadingTask = pdfjsLib.getDocument({ data: pdfData }); loadingTask.promise.then(function (pdf) { console.log('PDF loaded'); pdfDoc = pdf; pageEndNum = pdfDoc.numPages; document.getElementById('page_count').textContent = pageEndNum; // Fetch the first page renderPage(pageNum); }, function (reason) { // PDF loading error console.error(reason); }); function renderPage(pageNumber) { pdfDoc.getPage(pageNumber).then(function (page) { console.log('Page ' + pageNumber + ' loaded'); var scale = 1.5; var viewport = page.getViewport({ scale: scale }); // Prepare canvas using PDF page dimensions var canvas = document.getElementById('the-canvas'); var context = canvas.getContext('2d'); canvas.height = viewport.height; canvas.width = viewport.width; // Render PDF page into canvas context var renderContext = { canvasContext: context, viewport: viewport }; var renderTask = page.render(renderContext); renderTask.promise.then(function () { console.log('Page rendered'); }); }); document.getElementById('page_num').textContent = pageNumber; }; function safeAtob(base64Str) { // 检查输入字符串是否是有效的Base64编码 console.log(base64Str.length); const base64Regex = /^[A-Za-z0-9+/]+={0,2}$/; if (!base64Regex.test(base64Str)) { throw new Error('The string to be decoded is not correctly encoded.'); } // 如果输入字符串长度不是4的倍数,添加等号'=' while (base64Str.length % 4 !== 0) { base64Str += '='; } return atob(base64Str); } /** * Displays previous page. */ function onPrevPage() { if (pageNum <= pageStartNum) { return; } pageNum--; renderPage(pageNum); } document.getElementById('prev').addEventListener('click', onPrevPage); /** * Displays next page. */ function onNextPage() { if (pageNum >= pageEndNum) { return; } pageNum++; renderPage(pageNum); } document.getElementById('next').addEventListener('click', onNextPage); </script>
看下效果:
显示完成了
下一步结合上一篇:https://www.cnblogs.com/sun8134/p/18109237
我们给 PDF 文件实时加上水印
修改下我们文件转 base64 的方法:
public static string PdfWatermark2Base64(string inputPath, string watermarkImage, string watermarkTxt) { MemoryStream outputStream = new MemoryStream(); using (PdfReader existingPdf = new PdfReader(inputPath)) { using (PdfWriter newPdf = new PdfWriter(outputStream)) { using (PdfDocument pdfDocument = new PdfDocument(existingPdf, newPdf)) { Document document = new Document(pdfDocument); iText.Kernel.Geom.Rectangle pageSize; PdfCanvas canvas; var image = new iText.Layout.Element.Image(iText.IO.Image.ImageDataFactory.Create(watermarkImage)).ScaleToFit(200, 200); PdfFont fonts = PdfFontFactory.CreateFont(StandardFonts.TIMES_ROMAN); //PdfFont fontChinese; //var path = System.IO.Path.Combine("F:\\pdf", "font.ttf"); //fontChinese = PdfFontFactory.CreateFont(path, PdfEncodings.IDENTITY_H); int red = 51; int green = 53; int blue = 102; for (int i = 1; i <= pdfDocument.GetNumberOfPages(); i++) { PdfPage page = pdfDocument.GetPage(i); pageSize = page.GetPageSize(); canvas = new PdfCanvas(page); Paragraph p = new Paragraph(); p.Add(image); p.SetFont(fonts); p.Add(new Text("\r\n")); p.Add(new Text(watermarkTxt).SetFontSize(90).SetFontColor(new DeviceRgb((float)red / 255f, (float)green / 255f, (float)blue / 255f))); p.Add(new Text("\r\n")); p.Add(new Text(DateTime.Now.ToString("yyyy-MM-dd HH:mm")).SetFontSize(60).SetFontColor(ColorConstants.DARK_GRAY)); canvas.SaveState(); PdfExtGState gs1 = new PdfExtGState().SetFillOpacity(0.4f); canvas.SetExtGState(gs1); document.ShowTextAligned(p, pageSize.GetWidth() / 2 - 50, pageSize.GetHeight() / 2 + 50, pdfDocument.GetPageNumber(page), TextAlignment.CENTER, VerticalAlignment.MIDDLE, 45); } document.Close(); pdfDocument.Close(); newPdf.Close(); existingPdf.Close(); } } } byte[] extractedPdfData = ((MemoryStream)outputStream).ToArray(); string base64 = Convert.ToBase64String(extractedPdfData); outputStream.Close(); outputStream.Dispose(); return base64; }
在控制器里调用新方法:
public IActionResult Index() { DefaultModel dm=new DefaultModel(); dm.PdfBase64 = PdfHelper.PdfWatermark2Base64("F:\\pdf\\compressed.tracemonkey-pldi-09.pdf", "F:\\pdf\\netcore.png", "Asp.Net Core 8.0"); return View(dm); }
看下效果:
整体上虽然能看
但效果其实只能说一般
pdfjs 带了一个 viewer.html
基本包含了全功能,下一篇说下怎么改 viewer.html
作者:sun8134
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。