首页 > 解决方案 > 我可以使用 ScreenshotAsync 方法将屏幕截图保存到内存而不是磁盘吗?

问题描述

我正在使用 PuppeteerSharp 从本地托管的 HTML 模板生成 PDF,并希望 PDF 不可搜索,这意味着 PDF 确实只是 PDF 中的一个大图像。我选择采用这种方法是因为我想让文档更难被篡改。

我已经想出了一种生成纯图像 PDF 的技术。我访问并截取 HTML 页面的屏幕截图,将其存储到磁盘,从浏览器访问所述屏幕截图,最后从该图像生成 PDF。PDF 结果很好,但我想了解是否可以消除将图像存储到磁盘的需要。

下面的代码:

功能码

[FunctionName("pdftest")]
        public async Task<IActionResult> Run(
            [HttpTrigger(AuthorizationLevel.Anonymous, "get")] HttpRequest req,
            ILogger log)
        {
            log.LogInformation($"Browser path: {appInfo.BrowserExecutablePath}");

            ViewPortOptions vprtOpts = new ViewPortOptions()
            {
                DeviceScaleFactor = 2
            };

            var browser = await Puppeteer.LaunchAsync(new LaunchOptions
            {
                Headless = true,
                ExecutablePath = appInfo.BrowserExecutablePath,
                DefaultViewport = vprtOpts
            });

            var page = await browser.NewPageAsync();
            // access the HTML template
            await page.GoToAsync(@"C:\experiment\pdf\index.html");

            // where to save the screenshot
            var file = @"C:\experiment\pdf\index.png";

            // where to save the final PDF
            var file2 = @"C:\experiment\pdf\index2.pdf";
            PdfOptions opts = new PdfOptions()
            {
                PrintBackground = true,
                Width = "794px",
                Height = "1122px",
                Scale = 1
            };

            ScreenshotOptions scrOpts = new ScreenshotOptions()
            {
                FullPage = true,
            };

            await page.ScreenshotAsync(file, scrOpts);
            await page.GoToAsync(@"C:\experiment\pdf\index.png");
            var stream = await page.PdfStreamAsync(opts);
            await page.PdfAsync(file2, opts);
            await browser.CloseAsync();

            return new FileStreamResult(stream, "application/pdf");
        }

启动.cs

public class Startup : FunctionsStartup
{

    public override void Configure(IFunctionsHostBuilder builder)
    {
        var bfOptions = new BrowserFetcherOptions();
        if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
        {
            bfOptions.Path = Path.GetTempPath();
        }
        var bf = new BrowserFetcher(bfOptions);
        bf.DownloadAsync(BrowserFetcher.DefaultRevision).Wait();
        var info = new AppInfo
        {
            BrowserExecutablePath = bf.GetExecutablePath(BrowserFetcher.DefaultRevision)
        };

        var port = GetAvailablePort();
        info.RazorPagesServerPort = port;
        builder.Services.AddSingleton(info);

        var webHost = Host.CreateDefaultBuilder()
            .ConfigureWebHostDefaults(webBuilder =>
            {
                var scriptRoot = Environment.GetEnvironmentVariable("AzureWebJobsScriptRoot");
                System.Console.WriteLine($"Starting web server on port {port}");
                if (!string.IsNullOrEmpty(scriptRoot))
                {
                    webBuilder.UseContentRoot(scriptRoot);
                }

                webBuilder.UseUrls($"http://0.0.0.0:{port}")
                    .UseStartup<RazorPagesApp.Startup>();
            })
            .Build();

        webHost.Start();
    }

    private int GetAvailablePort()
    {
        // https://stackoverflow.com/a/150974/9035640
        var listener = new TcpListener(IPAddress.Loopback, 0);
        listener.Start();
        int availablePort = ((IPEndPoint)listener.LocalEndpoint).Port;
        listener.Stop();
        return availablePort;
    }
}

public class AppInfo
{
    public string BrowserExecutablePath { get; set; }
    public int RazorPagesServerPort { get; set; }
}

标签: c#puppeteer-sharp

解决方案


根据您拥有的文档,ScreenShotDataAsync它返回 a byte[]

byte[] data = await page.ScreenshotDataAsync(scrOpts);

还有ScreenshotStreamAsyncwhich 返回 a Stream

Stream stream = await page.ScreenshotStreamAsync(scrOpts);

推荐阅读