从较大的UIImage裁剪UIImage的一部分,并包括非图像部分

时间:2013-10-04 17:22:20

标签: ios uiscrollview uiimage ios7 crop

我想我可能有一个奇怪的请求,但希望有人可以提供帮助。我使用众所周知的UIScrollView + UIImageView来放大和缩小图像,以及平移。这工作得很好,但我们当前的项目需要能够裁剪图像,但如果图像小于裁剪矩形,还包括侧面的黑条。见下图。

我们希望捕获蓝色框内的所有内容,包括白色(由于不透明设置为YES,因此将为黑色)。

这适用于完全缩小的图像(白色只是UIImageView的额外空间)。 enter image description here

然而,当我们尝试放大图像并仅捕获该部分以及空白空间时,问题就出现了。 enter image description here

这导致以下图像 enter image description here

我们遇到的问题是我们需要能够创建一个与裁剪矩形完全相同的图像,无论是否存在图像的一部分。另一个问题是我们希望能够动态改变输出分辨率。宽高比为16:9,对于此示例kMaxWidth = 1136kMaxHeight = 639,但未来我们可能要求更大或更小的16:9分辨率。

以下是我到目前为止的功能:

- (UIImage *)createCroppedImageFromImage:(UIImage *)image {
    CGSize newRect = CGSizeMake(kMaxWidth, kMaxHeight);
    UIGraphicsBeginImageContextWithOptions(newRect, YES, 0.0);

    // 0 is the edge of the screen, to help with zooming
    CGFloat xDisplacement = ((abs(0 - imageView.frame.origin.x) * kMaxWidth) / (self.cropSize.width / self.scrollView.zoomScale) / self.scrollView.zoomScale);

    CGFloat yDisplacement = ((abs(self.cropImageView.frame.origin.y - imageView.frame.origin.y) * kMaxHeight) / (self.cropSize.height / self.scrollView.zoomScale) / self.scrollView.zoomScale);

    CGFloat newImageWidth = (self.image.size.width * kMaxWidth) / (self.cropSize.width / self.scrollView.zoomScale);
    CGFloat newImageHeight = (self.image.size.height * kMaxHeight) / (self.cropSize.height / self.scrollView.zoomScale);    
   [image drawInRect:CGRectMake(xDisplacement, 0, newImageWidth, newImageHeight)];
    UIImage *croppedImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    return croppedImage;
}

非常感谢任何帮助。

2 个答案:

答案 0 :(得分:3)

我最后只是截取屏幕截图,然后裁剪。它似乎运作良好。

- (UIImage *)cropImage {
    CGRect cropRect = self.cropOverlay.cropRect;
    UIGraphicsBeginImageContext(self.view.frame.size);

    [self.view.layer renderInContext:UIGraphicsGetCurrentContext()];
    UIImage *fullScreenshot = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();

    CGImageRef croppedImage = CGImageCreateWithImageInRect(fullScreenshot.CGImage, cropRect);
    UIImage *crop = [[UIImage imageWithCGImage:croppedImage] resizedImage:self.outputSize interpolationQuality:kCGInterpolationHigh];
    CGImageRelease(croppedImage);
    return crop;
}

如果使用的是iOS 7,则可以使用drawViewHierarchyInRect:afterScreenUpdates:,而不是renderInContext:

答案 1 :(得分:0)

我认为图像视图的翻译后的矩形计算不正确。由于UIImageView是UIScrollView中的子视图,因此您应该能够通过调用[scrollView convertRect:scrollView.bounds toView:imageView];来计算可见的rect。这将是图像视图的可见矩形。你现在需要的就是裁剪它。

-(UIImage*)cropImage:(UIImage*)img inRect:(CGRect)rect{
    CGImageRef cropped = CGImageCreateWithImageInRect(img.CGImage, rect);
    UIImage *image =  [UIImage imageWithCGImage:cropped];

    CGImageRelease(cropped);
    return image;
}

编辑:是的...我忘了提到裁剪应该在(0,1)坐标空间中完成。我已为您修改了裁剪功能,因此它会根据您提供的所有参数,UIScrollView中的UIImageView和图像来裁剪图像。

-(UIImage*)cropImage:(UIImage*)image inImageView:(UIImageView*)imageView scrollView:(UIScrollView*)scrollView{
    // get visible rect from image scrollview
    CGRect visibleRect = [scrollView convertRect:scrollView.bounds toView:imageView];
    UIImage* rCroppedImage;

    CALayer* maskLayer= [[CALayer alloc] init];

    maskLayer.contents= (id)image.CGImage;
    maskLayer.frame= CGRectMake(0, 0, visibleRect.size.width, visibleRect.size.height);

    CGRect rect= CGRectMake(visibleRect.origin.x / image.size.width,
                            visibleRect.origin.y / image.size.height,
                            visibleRect.size.width / image.size.width,
                            visibleRect.size.height / image.size.height);
    maskLayer.contentsRect= rect;
    UIGraphicsBeginImageContext(visibleRect.size);

    CGContextRef context= UIGraphicsGetCurrentContext();

    [maskLayer renderInContext:context];

    rCroppedImage= UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();

    return rCroppedImage;
}