вівторок, 16 червня 2015 р.

Тонкости crop’а UIImage

Иногда возникает необходимость вырезать часть изображения из UIImage (сделать crop). Обычно используется следующий подход:

- (UIImage)cropInRect:(CGRect)cropRect {
    CGImageRef imageRef = CGImageCreateWithImageInRect(self.CGImage, cropRect);
    UIImage cropped = [UIImage imageWithCGImage:imageRef scale:1. 
        orientation:self.imageOrientation];
    CGImageRelease(imageRef);
    return cropped;
}

Однако здесь есть одна проблема: данный метод работает только для изображений в обычной ориентации. Если же изображение повернуто, то будет вырезана не совсем правильная часть. Оригинальное изображение:

Вырезанная часть:

Тонкость состоит в том, что необходимо трансформировать координаты вырезаемой части в зависимости от ориентации изображения:

- (UIImage)cropInRect:(CGRect)cropRect {
    CGAffineTransform rectTransform;
    switch (self.imageOrientation) {
        case UIImageOrientationLeft:
            rectTransform = CGAffineTransformTranslate(CGAffineTransformMakeRotation(M_PI_2), 
                    0, -self.size.height);
            break;
        case UIImageOrientationRight:
            rectTransform = CGAffineTransformTranslate(CGAffineTransformMakeRotation(-M_PI_2), 
                    -self.size.width, 0);
            break;
        case UIImageOrientationDown:
            rectTransform = CGAffineTransformTranslate(CGAffineTransformMakeRotation(-M_PI), 
                    -self.size.width, -self.size.height);
            break;
        default:
            rectTransform = CGAffineTransformIdentity;
    };
    rectTransform = CGAffineTransformScale(rectTransform, self.scale, self.scale);
    CGImageRef imageRef = CGImageCreateWithImageInRect(self.CGImage, 
            CGRectApplyAffineTransform(cropRect, rectTransform));
    UIImage cropped = [UIImage imageWithCGImage:imageRef scale:1. 
        orientation:self.imageOrientation];
    CGImageRelease(imageRef);
    return cropped;
}

После этого вырезается правильная часть: