首页 > 编程语言 >ASP.NET Core 使用 pdfjs 加载 实时水印 base64 编码的 PDF

ASP.NET Core 使用 pdfjs 加载 实时水印 base64 编码的 PDF

时间:2024-04-03 10:01:52浏览次数:16  
标签:Core canvas ASP base64 new pdf var PDF page

先下载 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

标签:Core,canvas,ASP,base64,new,pdf,var,PDF,page
From: https://www.cnblogs.com/sun8134/p/18112018

相关文章

  • 界面控件DevExtreme JS & ASP.NET Core 2024年度产品规划预览(一)
    在本文中我们将介绍今年即将发布的v24.1附带的主要特性,这些特性既适用于DevExtreme JavaScript(Angular、React、Vue、jQuery),也适用于基于DevExtreme的ASP.NETMVC/Core控件。注意:本文中列出的功能和特性说明官方当前/预计的发展计划,此信息仅供参考之用,其中列出的功能/产品可......
  • coredump功能使用
    centos-stream9中的coredump功能开启需要在运行程序的连接中先将coredump大小设置为unlimited,否则默认是0无法生成coredump。ulimit-culimited查看/proc/sys/kernel/core_pattern,目前默认设置如下:表示当前生成coredump需要依据systemd-coredump的配置来生成,可以通过mans......
  • 将asp.net core 程序打包成docker镜像,并创建容器
    一、编写DockerfileFROMmcr.microsoft.com/dotnet/aspnet:7.0//指定基础镜像asp.netcore7COPYdist/appWORKDIR/appEXPOSE80/tcpENTRYPOINT["dotnet","App.dll"]二、将asp.netcore程序打包成镜像dockerbuild-t镜像名-fDockerfile三、创建容器1......
  • ASP.NET Zero Authenticate 性能问题
    前言​伴随着ASP.NETZero系统日渐运行,通过/api/TokenAuth/Authenticate获取Token的速度会逐渐变慢,到最后会呈现出一次获取会超过20秒或者导致超时的现象。先说结论导致问题产生的代码:​ TokenAuthController>CreateJwtClaims>AddTokenValidityKeyAsyncawait_userManag......
  • .netcore生命周期、消息管道
    .NETCore的初始化过程涉及多个步骤,这些步骤从应用程序的启动开始,一直到应用程序准备好处理请求。下面是一个简化的概述,描述了.NETCore应用程序(特别是ASP.NETCore应用程序)的初始化过程:启动主机(Host):.NETCore应用程序通过 CreateHostBuilder 方法(在Program.cs文件......
  • .NET Aspire 中的服务发现
    .NETAspire中的服务发现https://www.nuget.org/packages/Microsoft.Extensions.ServiceDiscovery.NETAspire中的服务发现.NETAspire包含了对于开发阶段和测试阶段配置服务发现的功能。该功能通过提供基于配置的服务端点解析器来实现,来自.NETAspireAppHost项目中的服......
  • .net core webapi统一修改日期时间的返回格式
    在写WebApi时,我们的日期时间往往是DateTime类型,如果直接返回,前端拿到的结果有可能会是这种格式:下面是如何将返回的DateTime字段统一改成自定义的格式首先创建一个自定义的JSON序列化器,定义一个继承System.Text.Json.Serialization.JsonConverter的类,实现Read和Write两个抽象方......
  • url图片转base64
    constbase64Str:string=awaitnewPromise(resolve=>{constimg=newImage()img.crossOrigin='anonymous';img.src=url;//图片链接img.onload=function(){constcanvas=document.createElement('canv......
  • docker-compose 部署OWASP Juice Shop + CTFd
    项目介绍1.OWASPJuiceShop原文OWASPJuiceShopisprobablythemostmodernandsophisticatedinsecurewebapplication!Itcanbeusedinsecuritytrainings,awarenessdemos,CTFsandasaguineapigforsecuritytools!JuiceShopencompassesvulnerabili......
  • C#/.NET/.NET Core优秀项目和框架2024年3月简报
    前言公众号每月定期推广和分享的C#/.NET/.NETCore优秀项目和框架(每周至少会推荐两个优秀的项目和框架当然节假日除外),公众号推文中有项目和框架的介绍、功能特点、使用方式以及部分功能截图等(打不开或者打开GitHub很慢的同学可以优先查看公众号推文,文末一定会附带项目和框架......