c# - 如何在 UWP 应用程序中打印 pdf 文件后减少内存消耗

标签 c# uwp uwp-xaml

我正在使用 Microsoft 的 PrintHelper(Microsoft.Toolkit.Uwp.Helpers.PrintHelper) 为我的应用程序打印 pdf。现在打印实际上是通过将 pdf 渲染到 BitmapImage 中,从而打印 BitmapImage 来工作的。这适用于少量页面。但是当页面数量增加时,用于渲染 BitmapImages 的内存消耗会增加。虽然我使用垃圾收集,但打印操作后内存不会释放。当执行打印次数过多时,应用程序会崩溃。

有什么方法可以减少这种内存泄漏或提高打印效率吗?

这是我的代码:

在此,函数 GetImages() 返回 BitmapImages。 PrintPreview 是显示位图图像的网格。

    public async Task PrintAsync()
    {
        GC.Collect();
        foreach (var image in await GetImages())
        {
            Grid grid = new Grid();
            var printpreview = new PrintPreview(image);
            grid.Children.Add(printpreview);

            printHelper.AddFrameworkElementToPrint(grid); printpreview = null;
            grid = null;
            GC.Collect();
        }
    }

即使我在打印操作后强制收集GC,内存也没有释放。

    private void PrintHelper_OnPrintSucceeded()
    {
        GC.Collect();
        printHelper.ClearListOfPrintableFrameworkElements();
        printHelper.Dispose();
        GC.SuppressFinalize(this);

    }

编辑:

下面是 GetImages() 函数。

    public async Task<IEnumerable<ImageSource>> GetImages(int qualityRatio = 2)
    {
        GC.Collect();
        if (pdf_stream != null)
        {
            StorageFolder myfolder = ApplicationData.Current.LocalFolder;
            StorageFile pdf_file;
            pdf_file = await myfolder.CreateFileAsync(filename + ".pdf", CreationCollisionOption.GenerateUniqueName);
            using (Stream outputStream = await pdf_file.OpenStreamForWriteAsync())
            {
                await pdf_stream.AsStreamForRead().CopyToAsync(outputStream);
            }
            var result = new List<ImageSource>();
            try
            {
                var document = await PdfDocument.LoadFromFileAsync(pdf_file);
                for (uint i = 0; i < document.PageCount; i++)
                {
                    using (var page = document.GetPage(i))
                    {
                        using (var memoryStream = new MemoryStream())
                        {
                            using (var randomStream = memoryStream.AsRandomAccessStream())
                            {
                                var image = new BitmapImage();
                                var options = new PdfPageRenderOptions
                                {
                                    DestinationWidth = (uint)page.Size.Width * (uint)qualityRatio,
                                    DestinationHeight = (uint)page.Size.Height * (uint)qualityRatio
                                };
                                await page.RenderToStreamAsync(randomStream, options);
                                image.SetSource(randomStream);
                                result.Add(image);
                            }
                        }
                    }
                }
            }
            catch { }
            return result;
        }
        return null;
    }

PrintPreview.xaml

<Page
x:Class="App.src.PrintPreview"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">

<Grid>
    <Image Source="{Binding}"   Stretch="Uniform" Margin="0"></Image>
</Grid>

PrintPreview.xaml.cs

public sealed partial class PrintPreview : Page
{
    public PrintPreview(ImageSource image)
    {
        this.InitializeComponent();
        this.DataContext = image;
    }
}

最佳答案

通过测试,可以额外创建一个Image控件,先将BitmapImage传给Image.Source,然后使用randomStream设置Source,会节省一些内存。

主页.xaml:

<Image x:Name="Output" Visibility="Collapsed" ></Image>

主页.cs:

using (var page = document.GetPage(i))
{
    var stream = new InMemoryRandomAccessStream();
    await page.RenderToStreamAsync(stream);
    BitmapImage src = new BitmapImage();
    Output.Source = src; // pass bitmapImage to Source
    await src.SetSourceAsync(stream);
    stream.Dispose();
    result.Add(src);
}

此外,我发现与使用流加载位图图像相比,使用urisource 可以节省更多内存。但是您需要将每个页面从 pdf 转换为 StorageFile 并将其保存在临时文件夹中,然后使用 UriSource 将其转换为 bitmapImage。比较复杂,不过也可以试试看。

关于c# - 如何在 UWP 应用程序中打印 pdf 文件后减少内存消耗,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58875913/

相关文章:

c# - uwp 如何一次调整模板项目源中项目的大小?

xaml - System.Type 作为转换器的属性 - 仅适用于代码隐藏中未使用的属性

c# - Foreach 循环导致 NullReferenceException

c# - 节省 SQL 数据库的时间

c# - 如何使用正则表达式模式替换以下字符串

c# - 属性 "VisualTree"只能设置一次

c# - UWP 自定义控件,不能使用绑定(bind),只有 x :Bind, 如何适配?

c# - 从 UWP C# 应用在文件资源管理器中打开文件夹

webview - UWP 应用程序 WebView 泄漏内存,无法清除图像

c# - 使用 Oracle DB 和 .NET 时的最佳实践