如何在将PDF页面渲染到CGBitmapContext中时减少内存使用量

本文关键字:CGBitmapContext 使用量 内存 PDF | 更新日期: 2023-09-27 18:34:08

我正在使用下面的代码来渲染PDF页面的预览。但是,它正在使用内存负载(每页2-3MB)。

在设备日志中,我看到:

<Error>: CGBitmapContextInfoCreate: unable to allocate 2851360 bytes for bitmap data

我真的不需要以每个颜色通道 8 位呈现位图。如何更改代码以使其以灰度或每通道更少的位数呈现?

我也可以使用一种解决方案,其中位图以 x/y 的最大分辨率呈现,然后将生成的图像缩放到请求的大小。无论如何,PDF 之后将由CATiledLayer详细呈现。

同样根据Apple的文档,如果无法创建上下文(由于内存),CGBitmapContextCreate()返回NIL。但是在 MonoTouch 中,只有构造函数来创建上下文,因此我无法检查创建是否失败。如果可以的话,我可以跳过伪装者的图像。

UIImage oBackgroundImage= null;
using(CGColorSpace oColorSpace = CGColorSpace.CreateDeviceRGB())
// This is the line that is causing the issue.
using(CGBitmapContext oContext = new CGBitmapContext(null, iWidth, iHeight, 8, iWidth * 4, oColorSpace, CGImageAlphaInfo.PremultipliedFirst))
{
    // Fill background white.
    oContext.SetFillColor(1f, 1f, 1f, 1f);
    oContext.FillRect(oTargetRect);
    // Calculate the rectangle to fit the page into. 
    RectangleF oCaptureRect = new RectangleF(0, 0, oTargetRect.Size.Width / fScaleToApply, oTargetRect.Size.Height / fScaleToApply);
    // GetDrawingTransform() doesn't scale up, that's why why let it calculate the transformation for a smaller area
    // if the current page is smaller than the area we have available (fScaleToApply > 1). Afterwards we scale up again.
    CGAffineTransform oDrawingTransform = oPdfPage.GetDrawingTransform(CGPDFBox.Media, oCaptureRect, 0, true);
    // Now scale context up to final size.
    oContext.ScaleCTM(fScaleToApply, fScaleToApply);
    // Concat the PDF transformation.
    oContext.ConcatCTM(oDrawingTransform);
    // Draw the page.
    oContext.InterpolationQuality = CGInterpolationQuality.Medium;
    oContext.SetRenderingIntent (CGColorRenderingIntent.Default);
    oContext.DrawPDFPage(oPdfPage);
    // Capture an image.
    using(CGImage oImage = oContext.ToImage())
    {
        oBackgroundImage = UIImage.FromImage( oImage );
    }
}

如何在将PDF页面渲染到CGBitmapContext中时减少内存使用量

我真的不需要以每个颜色通道 8 位呈现位图。

using(CGColorSpace oColorSpace = CGColorSpace.CreateDeviceRGB())

您是否尝试过提供不同的色彩空间?

其中位图以 x/y 的最大分辨率呈现

using(CGBitmapContext oContext = new CGBitmapContext(null, iWidth, iHeight, 8, iWidth * 4, oColorSpace, CGImageAlphaInfo.PremultipliedFirst))

您也可以控制位图大小以及直接影响位图所需内存量的其他参数。

同样根据Apple的文档,如果无法创建上下文(由于内存),则CGBitmapContextCreate()返回NIL。

如果返回无效对象(如 null),则 C# 实例的Handle等于 IntPtr.Zero 。对于任何 ObjC 对象都是如此,因为init可以返回nil,而 .NET 构造函数不能返回 null

同样根据Apple的文档,如果无法创建上下文(由于内存),则CGBitmapContextCreate()返回NIL。但是在 MonoTouch 中,只有构造函数来创建上下文,因此我无法检查创建是否失败。如果可以的话,我可以跳过伪装者的图像。

这实际上很容易:

CGBitmapContext context;
try {
    context = new CGBitmapContext (...);
} catch (Exception ex) {
    context = null;
}
if (context != null) {
    using (context) {
        ...
    }
}

或者您也可以在异常处理程序中将整个 using 子句括起来:

try {
    using (var context = new CGBitmapContext (...)) {
        ...
    }
} catch {
    // we failed
    oBackgroundImage = null;
}