我有一些代码来调整图像的大小,这样我就可以得到图像中心的缩放块-我用这个来获取一个UIImage,并返回一个小的,正方形的图像表示,类似于在照片应用程序的相册视图中看到的。(我知道我可以使用UIImageView和调整裁剪模式来实现相同的结果,但这些图像有时显示在UIWebViews中)。

我已经开始注意到这段代码中的一些崩溃,我有点难住了。我有两种不同的理论,不知道哪一种是正确的。

理论1)我通过绘制到目标尺寸的屏幕外图像上下文来实现裁剪。因为我想要图像的中心部分,所以我将传递给drawwinrect的CGRect参数设置为比图像上下文的边界更大的值。我希望这是符合规定的,但我是不是在试图掩盖其他我不应该触及的记忆?

理论2)我在后台线程中做所有这些。我知道UIKit的某些部分被限制在主线程中。我假设/希望绘制到屏幕外的视图不是其中之一。我错了吗?

(哦,我真怀念NSImage的drawwinrect:fromRect:operation:fraction:方法。)


当前回答

更新2014-05-28:我写这篇文章的时候,iOS 3左右还是热门的新事物,我相信现在有更好的方法来做到这一点,可能是内置的。正如很多人提到的,这种方法没有考虑到轮换;阅读一些额外的答案,并散布一些点赞的爱,让这个问题的回答对每个人都有帮助。

最初的反应:

我将把我对相同问题的回答复制/粘贴到其他地方:

没有一个简单的类方法可以做到这一点,但有一个函数可以使用来获得所需的结果:CGImageCreateWithImageInRect(CGImageRef, CGRect)将帮助您解决这个问题。

下面是一个简短的例子:

CGImageRef imageRef = CGImageCreateWithImageInRect([largeImage CGImage], cropRect);
// or use the UIImage wherever you like
[UIImageView setImage:[UIImage imageWithCGImage:imageRef]]; 
CGImageRelease(imageRef);

其他回答

关注@Arne的回答。 我只是固定到类别函数。把它放在UIImage的Category中。

-(UIImage*)cropImage:(CGRect)rect{

    UIGraphicsBeginImageContextWithOptions(rect.size, false, [self scale]);
    [self drawAtPoint:CGPointMake(-rect.origin.x, -rect.origin.y)];
    UIImage* cropped_image = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    return cropped_image;
}

更新2014-05-28:我写这篇文章的时候,iOS 3左右还是热门的新事物,我相信现在有更好的方法来做到这一点,可能是内置的。正如很多人提到的,这种方法没有考虑到轮换;阅读一些额外的答案,并散布一些点赞的爱,让这个问题的回答对每个人都有帮助。

最初的反应:

我将把我对相同问题的回答复制/粘贴到其他地方:

没有一个简单的类方法可以做到这一点,但有一个函数可以使用来获得所需的结果:CGImageCreateWithImageInRect(CGImageRef, CGRect)将帮助您解决这个问题。

下面是一个简短的例子:

CGImageRef imageRef = CGImageCreateWithImageInRect([largeImage CGImage], cropRect);
// or use the UIImage wherever you like
[UIImageView setImage:[UIImage imageWithCGImage:imageRef]]; 
CGImageRelease(imageRef);

我使用下面的方法。

  -(UIImage *)getNeedImageFrom:(UIImage*)image cropRect:(CGRect)rect
  {
    CGSize cropSize = rect.size;
    CGFloat widthScale =  
    image.size.width/self.imageViewOriginal.bounds.size.width;
    CGFloat heightScale = 
    image.size.height/self.imageViewOriginal.bounds.size.height;
    cropSize = CGSizeMake(rect.size.width*widthScale,  
    rect.size.height*heightScale);
    CGPoint  pointCrop = CGPointMake(rect.origin.x*widthScale, 
    rect.origin.y*heightScale);
    rect = CGRectMake(pointCrop.x, pointCrop.y, cropSize.width, 
    cropSize.height);
    CGImageRef subImage = CGImageCreateWithImageInRect(image.CGImage, rect);
    UIImage *croppedImage = [UIImage imageWithCGImage:subImage];
    CGImageRelease(subImage);
    return croppedImage;

}

斯威夫特5:

extension UIImage {
    func cropped(rect: CGRect) -> UIImage? {
        guard let cgImage = cgImage else { return nil }

        UIGraphicsBeginImageContextWithOptions(rect.size, false, 0)
        let context = UIGraphicsGetCurrentContext()

        context?.translateBy(x: 0.0, y: self.size.height)
        context?.scaleBy(x: 1.0, y: -1.0)
        context?.draw(cgImage, in: CGRect(x: rect.minX, y: rect.minY, width: self.size.width, height: self.size.height), byTiling: false)


        let croppedImage = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()

        return croppedImage
    }
}
CGSize size = [originalImage size];
int padding = 20;
int pictureSize = 300;
int startCroppingPosition = 100;
if (size.height > size.width) {
    pictureSize = size.width - (2.0 * padding);
    startCroppingPosition = (size.height - pictureSize) / 2.0; 
} else {
    pictureSize = size.height - (2.0 * padding);
    startCroppingPosition = (size.width - pictureSize) / 2.0;
}
// WTF: Don't forget that the CGImageCreateWithImageInRect believes that 
// the image is 180 rotated, so x and y are inverted, same for height and width.
CGRect cropRect = CGRectMake(startCroppingPosition, padding, pictureSize, pictureSize);
CGImageRef imageRef = CGImageCreateWithImageInRect([originalImage CGImage], cropRect);
UIImage *newImage = [UIImage imageWithCGImage:imageRef scale:1.0 orientation:originalImage.imageOrientation];
[m_photoView setImage:newImage];
CGImageRelease(imageRef);

我所见过的大多数响应只处理(x, y)的位置(0,0)。好吧,这是一种情况,但我希望我的裁剪操作居中。我花了一些时间才弄清楚WTF注释后面的那行。

让我们以纵向捕获的图像为例:

原始图像的高度高于它的宽度(哇,到目前为止还没有什么奇怪的!) CGImageCreateWithImageInRect方法在它自己的世界中想象的图像并不是一个真正的肖像,而是一个景观(这也是为什么如果你不使用imageWithCGImage构造函数中的方向参数,它将显示为180旋转)。 你可以把它想象成一个横向,(0,0)位置是图像的右上角。

希望这是有意义的!如果没有,尝试不同的值,你会发现在为你的cropRect选择正确的x、y、宽度和高度时,逻辑是颠倒的。