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>
        &nbsp; &nbsp;
        <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>



看下效果:

image  image



显示完成了

下一步结合上一篇: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);
}



看下效果:

image  image



整体上虽然能看

但效果其实只能说一般

pdfjs 带了一个 viewer.html

基本包含了全功能,下一篇说下怎么改 viewer.html

posted @ 2024-04-03 09:55  sun8134  阅读(155)  评论(0编辑  收藏  举报
分享按钮