iOS - CATiledLayer renderInContext: искаженное изображение

У меня есть UIScrollView с поддержкой CATiledLayer, который отображает действительно большое изображение. Чего я хотел бы добиться, так это перенести это представление в UIImage (чтобы использовать его в качестве фона для представления индикатора выполнения). Есть несколько проблем:

  • при "100%" зуме (видна вся картинка) вроде нормально
  • если я увеличу масштаб прокрутки, некоторые из плиток искажаются (масштаб и / или смещение плохие)
  • попытался воспроизвести его с помощью образца Apple PhotoScroller, который почти работает, за исключением того, что снятые изображения иногда имеют пикселизацию
  • Я не писал код, поэтому понятия не имею как это исправить

Проверял другие записи stackru относительно этого, но они не сильно помогли...

Код захвата изображения:

CGRect rect = [view bounds];
UIImage* img = nil;

if ([view isKindOfClass:[UIScrollView class]])
{
    UIScrollView* scrollview = (UIScrollView*)view;
    CGPoint contentOffset = scrollview.contentOffset;

    UIGraphicsBeginImageContextWithOptions(rect.size, view.opaque, 0.0);
    CGContextRef ctx = UIGraphicsGetCurrentContext();

    CGContextTranslateCTM(ctx, -contentOffset.x, -contentOffset.y);
    [view.layer renderInContext:ctx];

    img = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
}

И код drawRect: метод мозаичного представления:

- (void)drawRect:(CGRect)rect
{
    CGContextRef context = UIGraphicsGetCurrentContext();

    if (self.clipContent)
    {
        CGContextSaveGState(context);
        CGFloat color[4] = {1.0, 1.0f, 1.0f, 1.0f};
        CGContextSetFillColor(context, color);
        CGContextFillRect(context, self.bounds);

        CGRect clips[] = {
            CGRectMake(self.bounds.size.width / 2.0, 0,
                       self.bounds.size.height / 2.0 , self.bounds.size.width / 2.0)
        };

        CGContextClipToRects(context, clips, sizeof(clips) / sizeof(clips[0]));
    }

    CGFloat scale = CGContextGetCTM(context).a;
    CGSize tileSize = [_dataSource tileSize];

    double width = (double)tileSize.width / (double)scale;//pow(2.0, (int)log2(scale));
    double height = (double)tileSize.height / (double)scale;//pow(2.0, (int)log2(scale));

    int firstCol = floorf(CGRectGetMinX(rect) / width);
    int lastCol = floorf((CGRectGetMaxX(rect) - 1) / width);
    int firstRow = floorf(CGRectGetMinY(rect) / height);
    int lastRow = floorf((CGRectGetMaxY(rect) - 1) / height);

    for (int row = firstRow; row <= lastRow; row++) {
        for (int col = firstCol; col <= lastCol; col++) {
            UIImage* tileImage = [_dataSource tileForScale:scale row:row col:col];

            CGRect tileRect = CGRectMake(width * col, height * row, width, height);
            tileRect = CGRectIntersection(rect, tileRect);

            [tileImage drawInRect:tileRect];
        }
    }

    if (self.clipContent)
        CGContextRestoreGState(context);
}

Есть идеи?

1 ответ

Решение

После многих проб и ошибок выяснилось, что сама реализация Какао является неполной, поэтому проблема не может быть решена.

С выпуском iOS 7 появился новый метод:

[view drawViewHierarchyInRect:rect afterScreenUpdates:YES];

(вместо renderInContext), и это работает (изображение несколько размыто, но это приемлемый побочный эффект).

Другие вопросы по тегам