iOS: получите «Предупреждение о получении памяти» после использования изображения, созданного из PDF и используемого в качестве фона - PullRequest
3 голосов
/ 14 октября 2010

Задача: создать изображение из файла PDF в качестве быстрого предварительного просмотра фона для моего PDF, отображаемого с CATiledLayer (медленнее, с более высоким разрешением).Проблема: я получаю довольно быстрое предупреждение об ошибке на своем iPad "Предупреждение о получении памяти. Уровень = 1" и вскоре после "Предупреждение о получении памяти. Уровень = 2" .. затем приложение вылетает.

- (void) drawSinglePage:(CALayer *)layer inContext:(CGContextRef)ctx {
    CGContextSaveGState(ctx);
    CGContextSetRGBFillColor(ctx, 1.0, 1.0, 1.0, 1.0);
    CGContextFillRect(ctx, CGContextGetClipBoundingBox(ctx));
    @synchronized(self) {

        // Draw PDF for HighRes
        CGPDFPageRef page = CGPDFDocumentGetPage(page1, 1);
        CGRect pageRect = CGPDFPageGetBoxRect(page, kCGPDFCropBox);
        CGFloat scaleRatio = 960/pageRect.size.height;
        CGFloat yOffset = ((960-pageRect.size.height)/scaleRatio)+960;

        CGContextTranslateCTM(ctx, -(layer.bounds.size.width-pageRect.size.width)/2, yOffset);
        CGContextScaleCTM(ctx, scaleRatio, -scaleRatio);
        CGContextConcatCTM(ctx, CGPDFPageGetDrawingTransform(page, kCGPDFCropBox, layer.bounds, 0, true));
        CGContextDrawPDFPage(ctx, page);

        // Draw Background-Image as fast preview (PROBLEM HERE!!)
        UIGraphicsBeginImageContext(layer.bounds.size);
        CGContextRef context = UIGraphicsGetCurrentContext();

        CGContextSetRGBFillColor(context, 1.0, 1.0, 1.0, 1.0);
        CGRect prob = CGContextGetClipBoundingBox(context);
        CGContextFillRect(context, prob);

        CGContextSaveGState(context);
        CGContextSetInterpolationQuality(context, kCGInterpolationLow);
        CGContextTranslateCTM(context, -(layer.bounds.size.width-pageRect.size.width)/2, yOffset);
        CGContextScaleCTM(context, scaleRatio, -scaleRatio);
        CGContextConcatCTM(context, CGPDFPageGetDrawingTransform(page, kCGPDFCropBox, CGRectMake(0.0, 0.0, layer.bounds.size.width, layer.bounds.size.height), 0, true));
        CGContextDrawPDFPage(context, page);
        CGContextRestoreGState(context);
        UIImage *back = UIGraphicsGetImageFromCurrentImageContext();
        NSData *jpegDataFile = UIImageJPEGRepresentation(back, 0.2f);
        UIImage *smBack = [[UIImage alloc] initWithData:jpegDataFile];      
        UIGraphicsEndImageContext();

        // Now set the subview
        UIImageView *backgroundImageView = [[UIImageView alloc] initWithImage:smBack];
        backgroundImageView.frame = CGRectMake(0.0, 0.0, smBack.size.width, smBack.size.height);
        backgroundImageView.contentMode = UIViewContentModeTopLeft;
        backgroundImageView.opaque = YES;
        [self.view addSubview:backgroundImageView];
        [self.view sendSubviewToBack:backgroundImageView];
        [backgroundImageView release];

    }
    CGContextRestoreGState(ctx);
}

}

Примечание: если я не настрою фоновое изображение, все будет в порядке - так что я уверен, что должен что-то выпустить, но я попробовал все.На данный момент я понятия не имею.Примечание: «CGPDFDocumentRelease(page1)» будет вызываться в функции - (void)dealloc этого ViewController.

Ответы [ 2 ]

3 голосов
/ 14 октября 2010

Я не знаю, сколько раз вызывается ваш метод drawSinglePage:inContext:, но он будет каждый раз создавать новый вид изображения с изображением, не сохраняя при этом ссылки на него. Это означает, что второй вызов увеличит использование памяти, в то время как видно только одно изображение.

Таким образом, если этот метод вызывается несколько раз, вы должны либо повторно использовать представление изображения (set imageView.image = nil), либо удалить ранее созданное представление изображения перед созданием нового. Это освободит изображение, уже находящееся в памяти, что может помешать предупреждению памяти во время рисования страницы.

Также имейте в виду, что рисование страницы в формате PDF может каждый раз увеличивать объем используемой памяти более чем на 20 МБ. Таким образом, в зависимости от того, сколько памяти ваше приложение уже использует, это может вызвать предупреждение о памяти. Сохраняйте низкое использование памяти и не пытайтесь рисовать более одной страницы одновременно.

0 голосов
/ 16 июля 2012

Посмотрите на https://github.com/mindbrix/UIImage-PDF (BSD?), Они хорошо справляются с рендерингом PDF в UIImage.

Глядя на ваш код, я вижу, что вы не освобождаете CGPDFDocument после рисования. Обратите внимание, что в зависимости от документа CGPDFDocument может занимать значительный объем памяти, а для сжатия изображения iPad с сетчатки глаза с помощью UIImageJPEGRepresentation также требуется много памяти. Вы можете избежать этого давления памяти, если освободите все свои вещи (CGPDFPage, CGPDFDocument) непосредственно после рисования.

Также обратите внимание, что CGPDFDocument имеет внутренний кеш, который можно очистить только в случае его уничтожения и повторного создания. Сделайте это после получения предупреждения памяти, иначе вы в конечном итоге потерпите крах. (если PDF достаточно сложный.)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...