How to reduce memory usage when rendering a PDF page in CGBitmapContext?

I am using the following code to render a PDF page. However, it uses a lot of memory (2-3 MB per page).

In device logs, I see:

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

I really don't need the bitmap to display at 8 bits per color channel. How can I change the code to appear in grayscale or fewer bits per channel?

I would also be okay with a solution in which a bitmap is displayed with a maximum resolution of x / y, and then the resulting image is scaled to the required size. After that, the PDF will be displayed in detail using CATiledLayer.

Also, according to Apple documentation, CGBitmapContextCreate()returns NIL if the context cannot be created (due to memory). But in MonoTouch there is only a constructor for creating a context, so I can not check whether the creation was unsuccessful or not. If I were able, I could just skip the image of the applicant.

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 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 );
    }
}
+3
source share
2 answers

I really don't need the bitmap to display at 8 bits per color channel.

...

using(CGColorSpace oColorSpace = CGColorSpace.CreateDeviceRGB())

Have you tried to provide a different color space?

where the bitmap is displayed with a maximum resolution of x / y

...

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

You can also control the size of the bitmap and other parameters that directly affect the amount of memory required by the bitmap.

, Apple, CGBitmapContextCreate() NIL, (- ).

(, null), # Handle IntPtr.Zero. ObjC, init nil, .NET null.

+2

, Apple, CGBitmapContextCreate() NIL, (- ). MonoTouch , , . , .

:

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

if (context != null) {
    using (context) {
        ...
    }
}

use :

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

All Articles