CGContextDrawImage ЧРЕЗВЫЧАЙНО медленный после того, как в него нарисован большой UIImage

Похоже, что CGContextDrawImage (CGContextRef, CGRect, CGImageRef) выполняет НАМНОГО ХУЖЕ при отрисовке CGImage, созданного CoreGraphics (то есть с CGBitmapContextCreateImage), чем при отрисовке CGImage, который поддерживает UIImage. См. Этот метод тестирования:

-(void)showStrangePerformanceOfCGContextDrawImage
{
    ///Setup : Load an image and start a context:
    UIImage *theImage = [UIImage imageNamed:@"reallyBigImage.png"];
    UIGraphicsBeginImageContext(theImage.size);
    CGContextRef ctxt = UIGraphicsGetCurrentContext();    
    CGRect imgRec = CGRectMake(0, 0, theImage.size.width, theImage.size.height);


    ///Why is this SO MUCH faster...
    NSDate * startingTimeForUIImageDrawing = [NSDate date];
    CGContextDrawImage(ctxt, imgRec, theImage.CGImage);  //Draw existing image into context Using the UIImage backing    
    NSLog(@"Time was %f", [[NSDate date] timeIntervalSinceDate:startingTimeForUIImageDrawing]);

    /// Create a new image from the context to use this time in CGContextDrawImage:
    CGImageRef theImageConverted = CGBitmapContextCreateImage(ctxt);

    ///This is WAY slower but why??  Using a pure CGImageRef (ass opposed to one behind a UIImage) seems like it should be faster but AT LEAST it should be the same speed!?
    NSDate * startingTimeForNakedGImageDrawing = [NSDate date];
    CGContextDrawImage(ctxt, imgRec, theImageConverted);
    NSLog(@"Time was %f", [[NSDate date] timeIntervalSinceDate:startingTimeForNakedGImageDrawing]);


}

Итак, я предполагаю, что вопрос в следующем: №1, что может вызывать это, и №2, есть ли способ обойти это, то есть другие способы создания CGImageRef, которые могут быть быстрее? Я понимаю, что могу сначала преобразовать все в UIImages, но это такое уродливое решение. У меня уже есть CGContextRef.

ОБНОВЛЕНИЕ: Это не обязательно верно при рисовании небольших изображений? Это может быть признаком того, что эта проблема усиливается, когда используются большие изображения (например, полноразмерные фото с камеры). 640x480 кажется очень похожим с точки зрения времени выполнения для любого метода

ОБНОВЛЕНИЕ 2: Хорошо, я обнаружил кое-что новое ... На самом деле это НЕ поддержка CGImage, которая меняет производительность. Я могу изменить порядок двух шагов и заставить метод UIImage вести себя медленно, тогда как «голое» CGImage будет очень быстрым. Кажется, что бы вы ни играли вторым, производительность будет ужасной. Кажется, это так, ЕСЛИ я не освободил память, вызвав CGImageRelease для изображения, созданного с помощью CGBitmapContextCreateImage.Тогда метод, поддерживаемый UIImage, впоследствии будет быстрым. Обратное - это неправда. Что дает? «Переполненная» память не должна так влиять на производительность, не так ли?

ОБНОВЛЕНИЕ 3: Слишком рано заговорил. Предыдущее обновление справедливо для изображений размером 2048x2048, но при увеличении до 1936x2592 (размер камеры) голый метод CGImage по-прежнему работает медленнее, независимо от порядка операций или ситуации с памятью. Возможно, существуют некоторые внутренние ограничения CG, которые делают изображение 16 МБ эффективным, тогда как изображение 21 МБ не может быть эффективно обработано. Его размер буквально в 20 раз медленнее отрисовки, чем у 2048x2048. Каким-то образом UIImage предоставляет свои данные CGImage намного быстрее, чем чистый объект CGImage. o.O

ОБНОВЛЕНИЕ 4: Я подумал, что это может быть связано с каким-то кешированием памяти, но результаты будут такими же, независимо от того, загружен ли UIImage с некэширующим [UIImage imageWithContentsOfFile], как если бы использовалось [UIImage imageNamed].

ОБНОВЛЕНИЕ 5 (День 2): После создания вопросов, на которые были даны ответы вчера, сегодня у меня что-то твердое. Что я могу сказать с уверенностью, так это следующее:

  • CGImages, стоящие за UIImage, не используют альфа. (kCGImageAlphaNoneSkipLast). Я подумал, что, возможно, их рисовать быстрее, потому что мой контекст БЫЛ с использованием альфы. Поэтому я изменил контекст, чтобы использовать kCGImageAlphaNoneSkipLast. Это делает рисование НАМНОГО быстрее, ЕСЛИ:
  • Рисование в CGContextRef с UIImage ПЕРВЫМ, замедляет ВСЕ последующие рисования изображений

Я доказал это 1) сначала создав не-альфа-контекст (1936x2592). 2) Заполните его произвольно раскрашенными квадратами 2х2.3) Полнокадровая отрисовка CGImage в этом контексте была БЫСТРОЙ (0,17 секунды). 4) Повторный эксперимент, но с заполнением контекста нарисованным CGImage, поддерживающим UIImage. Последующее рисование полнокадрового изображения длилось 6+ секунд. SLOWWWWW.

Каким-то образом рисование в контексте с (Large) UIImage резко замедляет все последующие рисования в этом контексте.

28
задан typewriter 27 September 2011 в 20:01
поделиться