裁剪UIImage


209

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

我已经开始注意到这段代码中的某些崩溃,我有些困惑。我有两种不同的理论,我想知道两者中的任何一种都没有。

理论1)我通过绘制到目标尺寸的屏幕外图像上下文来实现裁剪。由于我需要图像的中心部分,因此将CGRect传递的参数设置为drawInRect大于图像上下文边界的参数。我本以为这是犹太洁食,但我是不是想利用我不应该碰到的其他记忆?

理论2)我正在后台线程中完成所有这些工作。我知道UIKit的某些部分仅限于主线程。我以为/希望绘制到屏幕外的视图不是其中之一。我错了吗?

(哦,我怎么想念NSImage's drawInRect:fromRect:operation:fraction:方法。)


如果要诊断崩溃,则应在调试器下运行该应用程序,并记下崩溃时发生的情况。您甚至还没有确定是否由于异常的指针而引发了异常或正在获取EXC_BAD_ACCESS。一旦知道了,就可以开始进行理论了。
benzado

很公平。尽管在崩溃日志中确实有EXC_BAD_ACCESS消息,但我没有在调试器下对此进行重新设置。当我发布此内容时,我的假设是我在实现中犯了一个愚蠢的错误,有人会跳上它(就像忘记剪切路径一样)。
Jablair

尽管有以下优点和答案,但NSHipster上对技术及其性能进行了很好的调查:nshipster.com/image-resizing。我中的纯粹主义者想使用CIImage,但实用主义者选择了UIKit /图像上下文。
克里斯·康诺夫

Answers:


236

2014年5月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);

13
如果将imageOrientation设置为除up以外的任何值,CGImage则相对于旋转,UIImage则裁剪矩形将是错误的。您可以相应地旋转裁剪矩形,但是新创建的矩形UIImageimageOrientation向上CGImage旋转,以便裁剪后的矩形在其中旋转。
zoul 2010年

25
我想指出的是,在视网膜显示器上,您需要使用此方法将cropRect的宽度和高度加倍。我碰到的东西。
petrocket 2011年

21
使它可以在任何方向使用:[UIImage imageWithCGImage:imageRef scale:largeImage.scale orientation:largeImage.imageOrientation];
Nicos Karalis

3
您应该添加对Retina的支持!
马里奥·卡瓦略

1
@NicosKaralis只会将其旋转到正确的方向。但是,您正在裁剪图像的区域仍然是错误的。
Tim Bodeit 2013年

90

要在保持相同比例和方向的同时裁剪视网膜图像,请在UIImage类别(iOS 4.0及更高版本)中使用以下方法:

- (UIImage *)crop:(CGRect)rect {
    if (self.scale > 1.0f) {
        rect = CGRectMake(rect.origin.x * self.scale,
                          rect.origin.y * self.scale,
                          rect.size.width * self.scale,
                          rect.size.height * self.scale);
    }

    CGImageRef imageRef = CGImageCreateWithImageInRect(self.CGImage, rect);
    UIImage *result = [UIImage imageWithCGImage:imageRef scale:self.scale orientation:self.imageOrientation];
    CGImageRelease(imageRef);
    return result;
}

14
您可以在这里杀死条件条件,并且总是乘以self.scale,不是吗?
Michael Mior 2012年

2
迈克尔,您说的没错,但我认为上述解决方案在非视网膜设备上要快一点,因为它只执行一次检查,而不是四个乘法加一个赋值。在视网膜设备上,仅是一次布尔检查就超过了必要,因此这是个人喜好或目标匹配的问题。
CGee

2
CGImageRelease(imageRef);启用ARC的情况下使用是否正确?
CGee 2013年


3
实际上4次乘法可能比评估一个条件快:)在现代CPU上,可以很好地优化乘法,而只能预测条件。但是你是对的,这是一个偏好问题。我更喜欢短/简单的代码,因为它增加了可读性。
marsbear 2015年

65

您可以创建UIImage类别,并在需要的地方使用它。基于HitScans的响应和评论。

@implementation UIImage (Crop)

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

    rect = CGRectMake(rect.origin.x*self.scale, 
                      rect.origin.y*self.scale, 
                      rect.size.width*self.scale, 
                      rect.size.height*self.scale);       

    CGImageRef imageRef = CGImageCreateWithImageInRect([self CGImage], rect);
    UIImage *result = [UIImage imageWithCGImage:imageRef 
                                          scale:self.scale 
                                    orientation:self.imageOrientation]; 
    CGImageRelease(imageRef);
    return result;
}

@end

您可以通过以下方式使用它:

UIImage *imageToCrop = <yourImageToCrop>;
CGRect cropRect = <areaYouWantToCrop>;   

//for example
//CGRectMake(0, 40, 320, 100);

UIImage *croppedImage = [imageToCrop crop:cropRect];

3
不应该[[UIScreen mainScreen] scale]self.scale吗?图像的比例可能与屏幕的比例不同。
Michael Mior 2012年

嗨,我尝试了您的答案,No visible @interface for 'UIImage' declares the selector 'crop'即使我将.h和.m类别文件放入了我的项目,并将.h导入了我正在使用该类别的类中,它也给了我。任何想法?
阿里

解决它。我错过了将方法标头放在UIImage + Crop.h文件中。
阿里

我想将图像裁剪为圆形。这样我们只能看到圆形路径,而其他路径保持透明。
阿尔法2013年

比你可以使用CGImageCreateWithMask或CGImageCreateWithMaskingColors代替CGImageCreateWithImageInRect
维勒姆·库尔兹

54

Swift 3版本

func cropImage(imageToCrop:UIImage, toRect rect:CGRect) -> UIImage{
    
    let imageRef:CGImage = imageToCrop.cgImage!.cropping(to: rect)!
    let cropped:UIImage = UIImage(cgImage:imageRef)
    return cropped
}


let imageTop:UIImage  = UIImage(named:"one.jpg")! // add validation

在此处输入图片说明

借助此桥函数CGRectMake-> CGRect此答案的信用由回答@rob mayoff):

 func CGRectMake(_ x: CGFloat, _ y: CGFloat, _ width: CGFloat, _ height: CGFloat) -> CGRect {
    return CGRect(x: x, y: y, width: width, height: height)
}

用法是:

if var image:UIImage  = UIImage(named:"one.jpg"){
   let  croppedImage = cropImage(imageToCrop: image, toRect: CGRectMake(
        image.size.width/4,
        0,
        image.size.width/2,
        image.size.height)
    )
}

输出:

在此处输入图片说明


不知道为什么投票失败,我认为这是一个很好的答案。我唯一能想到的是它不处理缩放,因此如果您具有@ 2x / @ 3x图像且函数名称不匹配,它将无法使用。
威廉·T。

4
您需要guard第一行以防万一UIImage.CGImage返回,nil以及为什么使用varwhen let可以正常工作。
NoodleOfDeath

但是,这是正确的,但是请cropping(to:)非常仔细地阅读文档。所得到的结果CGImage强烈参考了CGImage从中收获的更大的结果。因此,如果您只想保留裁剪后的图像而又不需要原始图像,请查看其他解决方案。
jsadler '17

这不适用于带有方向标签的图像。裁剪区域无法正确旋转。
Max

1
@Max,这是因为cgImage没有方向支持。如果UIImage的是具有right那么cgImage应该由90度旋转CCW,因此作物RECT应当太旋转
MK容

49

这是我的UIImage裁剪实现,它遵循imageOrientation属性。所有方向都经过彻底测试。

inline double rad(double deg)
{
    return deg / 180.0 * M_PI;
}

UIImage* UIImageCrop(UIImage* img, CGRect rect)
{
    CGAffineTransform rectTransform;
    switch (img.imageOrientation)
    {
        case UIImageOrientationLeft:
            rectTransform = CGAffineTransformTranslate(CGAffineTransformMakeRotation(rad(90)), 0, -img.size.height);
            break;
        case UIImageOrientationRight:
            rectTransform = CGAffineTransformTranslate(CGAffineTransformMakeRotation(rad(-90)), -img.size.width, 0);
            break;
        case UIImageOrientationDown:
            rectTransform = CGAffineTransformTranslate(CGAffineTransformMakeRotation(rad(-180)), -img.size.width, -img.size.height);
            break;
        default:
            rectTransform = CGAffineTransformIdentity;
    };
    rectTransform = CGAffineTransformScale(rectTransform, img.scale, img.scale);

    CGImageRef imageRef = CGImageCreateWithImageInRect([img CGImage], CGRectApplyAffineTransform(rect, rectTransform));
    UIImage *result = [UIImage imageWithCGImage:imageRef scale:img.scale orientation:img.imageOrientation];
    CGImageRelease(imageRef);
    return result;
}

7
implicit declaration of function 'rad' is invalid in c99可以通过替换以下警告来消除警告:rad(90),rad(-90),rad(-180)-> M_PI_2,-M_PI_2,-_ M_PI
Sound Blaster

哎呀,对不起。在源代码片段中添加了rad()实用程序功能。
Sergii Rudchenko 2013年

contains undefined reference for architecture armv7我想念图书馆吗?CoreGraphics已导入。
鲍勃·斯普林

1
@SergiiRudchenko“所有方向都经过全面测试。” -这包括镜像方向吗?
Tim Bodeit

@BobSpryn不,您不会缺少图书馆。虽然我无法解释错误的含义,但像SoundBlaster所建议的那样,替换rad()也可以修复此错误。
Tim Bodeit 2013年

39

抬头:所有这些答案都假设一个CGImage支持图像的对象。

image.CGImage如果UIImage是以a为后缀,则可以返回nil,如果CIImage使用来创建此图片,则可能会返回nil CIFilter

在这种情况下,您可能必须在新的上下文中绘制图像,然后返回该图像(slow)。

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

5
这正是我所需要的,因此在所有情况下都可以使用,因此比其他任何解决方案都更好!
大卫·汤普森

2
第一行中的image.size应该是rect.size UIGraphicsBeginImageContextWithOptions(rect.size,false,image.scale);
Brett

2
谢谢布雷特,一定在那里。我更新了代码以包含此修复程序。
colinta 2014年

为什么-rect.origin.x不仅是rect.origin.x?
侵略者

2
因为我们在播种;换句话说,'rect'arg表示“我希望新图像的左上角从[10,10]开始”。为此,我们绘制图像,使[10,10]位于新图像的原点。
colinta

35

此处没有答案能正确处理所有比例和旋转问题。这是到目前为止所有内容的综合,是iOS7 / 8以来的最新信息。它应作为方法包含在UIImage的类别中。

- (UIImage *)croppedImageInRect:(CGRect)rect
{
    double (^rad)(double) = ^(double deg) {
        return deg / 180.0 * M_PI;
    };

    CGAffineTransform rectTransform;
    switch (self.imageOrientation) {
        case UIImageOrientationLeft:
            rectTransform = CGAffineTransformTranslate(CGAffineTransformMakeRotation(rad(90)), 0, -self.size.height);
            break;
        case UIImageOrientationRight:
            rectTransform = CGAffineTransformTranslate(CGAffineTransformMakeRotation(rad(-90)), -self.size.width, 0);
            break;
        case UIImageOrientationDown:
            rectTransform = CGAffineTransformTranslate(CGAffineTransformMakeRotation(rad(-180)), -self.size.width, -self.size.height);
            break;
        default:
            rectTransform = CGAffineTransformIdentity;
    };
    rectTransform = CGAffineTransformScale(rectTransform, self.scale, self.scale);

    CGImageRef imageRef = CGImageCreateWithImageInRect([self CGImage], CGRectApplyAffineTransform(rect, rectTransform));
    UIImage *result = [UIImage imageWithCGImage:imageRef scale:self.scale orientation:self.imageOrientation];
    CGImageRelease(imageRef);

    return result;
}

1
为什么这个答案不被更多支持?我尝试了以上所有答案,然后遇到了很多问题(特别是从UIImage转换为CIImage并丢失了正确的转换数据)。这是对我有用的唯一一个!
侵略者

1
感谢@Aggressor,很高兴这对您有用。我的答案仅在一个月前发布,而其中许多答案已经存在5年了。我猜这可以解释为什么缺乏可比的投票支持。
awolf

我正在使用它在图像上滑动过滤器(例如,如何操作),并且出现了轻微的缩放问题。您的代码中是否有任何内容可以建议我看看哪些可能导致此缩放错误?我贴我的解决方案,它在这里使用代码:stackoverflow.com/questions/23319497/...
侵略者的

一个非常有用的功能,谢谢。有什么技巧可以修改以使焦点集中在图像的中心部分?
私人

这应该是答案。
horseshoe7

17

awolf的答案的Swift版本,对我有用:

public extension UIImage {
    func croppedImage(inRect rect: CGRect) -> UIImage {
        let rad: (Double) -> CGFloat = { deg in
            return CGFloat(deg / 180.0 * .pi)
        }
        var rectTransform: CGAffineTransform
        switch imageOrientation {
        case .left:
            let rotation = CGAffineTransform(rotationAngle: rad(90))
            rectTransform = rotation.translatedBy(x: 0, y: -size.height)
        case .right:
            let rotation = CGAffineTransform(rotationAngle: rad(-90))
            rectTransform = rotation.translatedBy(x: -size.width, y: 0)
        case .down:
            let rotation = CGAffineTransform(rotationAngle: rad(-180))
            rectTransform = rotation.translatedBy(x: -size.width, y: -size.height)
        default:
            rectTransform = .identity
        }
        rectTransform = rectTransform.scaledBy(x: scale, y: scale)
        let transformedRect = rect.applying(rectTransform)
        let imageRef = cgImage!.cropping(to: transformedRect)!
        let result = UIImage(cgImage: imageRef, scale: scale, orientation: imageOrientation)
        return result
    }
}

10
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评论之后的内容。

让我们以纵向拍摄的图像为例:

  1. 原始图像的高度高于其宽度(哦,到目前为止,还不足为奇!)
  2. CGImageCreateWithImageInRect方法在自己的世界中想象的图像虽然不是真正的人像,但是却是风景(这就是为什么如果不在imageWithCGImage构造函数中使用direction参数,它将显示为180度旋转)。
  3. 因此,您应该想象一下它是风景,(0,0)位置是图像的右上角。

希望有道理!如果没有,请尝试不同的值,当您为cropRect选择正确的x,y,宽度和高度时,您会发现逻辑是相反的。


8

迅捷3

extension UIImage {
    func crop(rect: CGRect) -> UIImage? {
        var scaledRect = rect
        scaledRect.origin.x *= scale
        scaledRect.origin.y *= scale
        scaledRect.size.width *= scale
        scaledRect.size.height *= scale
        guard let imageRef: CGImage = cgImage?.cropping(to: scaledRect) else {
            return nil
        }
        return UIImage(cgImage: imageRef, scale: scale, orientation: imageOrientation)
    }
}

7

迅速扩展

extension UIImage {
    func crop(var rect: CGRect) -> UIImage {
        rect.origin.x*=self.scale
        rect.origin.y*=self.scale
        rect.size.width*=self.scale
        rect.size.height*=self.scale

        let imageRef = CGImageCreateWithImageInRect(self.CGImage, rect)
        let image = UIImage(CGImage: imageRef, scale: self.scale, orientation: self.imageOrientation)!
        return image
    }
}

4

就精度,像素缩放...而言,在Swift中裁剪UIImage的最佳解决方案:

private func squareCropImageToSideLength(let sourceImage: UIImage,
    let sideLength: CGFloat) -> UIImage {
        // input size comes from image
        let inputSize: CGSize = sourceImage.size

        // round up side length to avoid fractional output size
        let sideLength: CGFloat = ceil(sideLength)

        // output size has sideLength for both dimensions
        let outputSize: CGSize = CGSizeMake(sideLength, sideLength)

        // calculate scale so that smaller dimension fits sideLength
        let scale: CGFloat = max(sideLength / inputSize.width,
            sideLength / inputSize.height)

        // scaling the image with this scale results in this output size
        let scaledInputSize: CGSize = CGSizeMake(inputSize.width * scale,
            inputSize.height * scale)

        // determine point in center of "canvas"
        let center: CGPoint = CGPointMake(outputSize.width/2.0,
            outputSize.height/2.0)

        // calculate drawing rect relative to output Size
        let outputRect: CGRect = CGRectMake(center.x - scaledInputSize.width/2.0,
            center.y - scaledInputSize.height/2.0,
            scaledInputSize.width,
            scaledInputSize.height)

        // begin a new bitmap context, scale 0 takes display scale
        UIGraphicsBeginImageContextWithOptions(outputSize, true, 0)

        // optional: set the interpolation quality.
        // For this you need to grab the underlying CGContext
        let ctx: CGContextRef = UIGraphicsGetCurrentContext()
        CGContextSetInterpolationQuality(ctx, kCGInterpolationHigh)

        // draw the source image into the calculated rect
        sourceImage.drawInRect(outputRect)

        // create new image from bitmap context
        let outImage: UIImage = UIGraphicsGetImageFromCurrentImageContext()

        // clean up
        UIGraphicsEndImageContext()

        // pass back new image
        return outImage
}

用于调用此函数的说明:

let image: UIImage = UIImage(named: "Image.jpg")!
let squareImage: UIImage = self.squareCropImageToSideLength(image, sideLength: 320)
self.myUIImageView.image = squareImage

注意:在“ Cocoanetics”博客上可以找到用Objective-C编写的初始源代码。


3

下面的代码段可能会有所帮助。

import UIKit

extension UIImage {
    func cropImage(toRect rect: CGRect) -> UIImage? {
        if let imageRef = self.cgImage?.cropping(to: rect) {
            return UIImage(cgImage: imageRef)
        }
        return nil
    }
}

2

看起来有些奇怪,但效果很好,并考虑了图像方向:

var image:UIImage = ...

let img = CIImage(image: image)!.imageByCroppingToRect(rect)
image = UIImage(CIImage: img, scale: 1, orientation: image.imageOrientation)

1
但显然会破坏规模
Sulthan

2

斯威夫特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
    }
}

1
- (UIImage *)getSubImage:(CGRect) rect{
    CGImageRef subImageRef = CGImageCreateWithImageInRect(self.CGImage, rect);
    CGRect smallBounds = CGRectMake(rect.origin.x, rect.origin.y, CGImageGetWidth(subImageRef), CGImageGetHeight(subImageRef));

    UIGraphicsBeginImageContext(smallBounds.size);
    CGContextRef context = UIGraphicsGetCurrentContext();
    CGContextDrawImage(context, smallBounds, subImageRef);
    UIImage* smallImg = [UIImage imageWithCGImage:subImageRef];
    UIGraphicsEndImageContext();

    return smallImg;
}

1
 (UIImage *)squareImageWithImage:(UIImage *)image scaledToSize:(CGSize)newSize {
    double ratio;
    double delta;
    CGPoint offset;

    //make a new square size, that is the resized imaged width
    CGSize sz = CGSizeMake(newSize.width, newSize.width);

    //figure out if the picture is landscape or portrait, then
    //calculate scale factor and offset
    if (image.size.width > image.size.height) {
        ratio = newSize.width / image.size.width;
        delta = (ratio*image.size.width - ratio*image.size.height);
        offset = CGPointMake(delta/2, 0);
    } else {
        ratio = newSize.width / image.size.height;
        delta = (ratio*image.size.height - ratio*image.size.width);
        offset = CGPointMake(0, delta/2);
    }

    //make the final clipping rect based on the calculated values
    CGRect clipRect = CGRectMake(-offset.x, -offset.y,
                                 (ratio * image.size.width) + delta,
                                 (ratio * image.size.height) + delta);


    //start a new context, with scale factor 0.0 so retina displays get
    //high quality image
    if ([[UIScreen mainScreen] respondsToSelector:@selector(scale)]) {
        UIGraphicsBeginImageContextWithOptions(sz, YES, 0.0);
    } else {
        UIGraphicsBeginImageContext(sz);
    }
    UIRectClip(clipRect);
    [image drawInRect:clipRect];
    UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();

    return newImage;
}

1

在iOS9.2SDK上,我使用以下方法将帧从UIView转换为UIImage

-(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;
}

1

Swift 2.0更新(CIImage兼容性)

扩展Maxim's Answer,但也可以在您的图像CIImage基于的情况下使用。

public extension UIImage {
    func imageByCroppingToRect(rect: CGRect) -> UIImage? {
        if let image = CGImageCreateWithImageInRect(self.CGImage, rect) {
            return UIImage(CGImage: image)
        } else if let image = (self.CIImage)?.imageByCroppingToRect(rect) {
            return UIImage(CIImage: image)
        }
       return nil
   }
}

1

这是基于Noodles答案的更新的Swift 3版本

func cropping(to rect: CGRect) -> UIImage? {

    if let cgCrop = cgImage?.cropping(to: rect) {
        return UIImage(cgImage: cgCrop)
    }
    else if let ciCrop = ciImage?.cropping(to: rect) {
        return UIImage(ciImage: ciCrop)
    }

    return nil
}

1

关注@Arne的答案。我只是固定到类别功能。将其放在UIImage的类别中。

-(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;
}

0

我对其他解决方案不满意,因为它们要么花了很多时间(使用了比必要的功率更多的功率),要么出现了方向问题。这是我用于从UIImage *图像缩放的正方形croppedImage的内容。

CGFloat minimumSide = fminf(image.size.width, image.size.height);
CGFloat finalSquareSize = 600.;

//create new drawing context for right size
CGRect rect = CGRectMake(0, 0, finalSquareSize, finalSquareSize);
CGFloat scalingRatio = 640.0/minimumSide;
UIGraphicsBeginImageContext(rect.size);

//draw
[image drawInRect:CGRectMake((minimumSide - photo.size.width)*scalingRatio/2., (minimumSide - photo.size.height)*scalingRatio/2., photo.size.width*scalingRatio, photo.size.height*scalingRatio)];

UIImage *croppedImage = UIGraphicsGetImageFromCurrentImageContext();

UIGraphicsEndImageContext();

0

我使用下面的方法。

  -(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;

}


0

看看https://github.com/vvbogdan/BVCropPhoto

-(UIImage *)croppedImage {
    CGFloat比例= self.sourceImage.size.width / self.scrollView.contentSize.width;

    UIImage * finalImage = nil;
    CGRect targetFrame = CGRectMake((self.scrollView.contentInset.left + self.scrollView.contentOffset.x)*比例尺,
            (self.scrollView.contentInset.top + self.scrollView.contentOffset.y)*比例尺,
            self.cropSize.width *比例尺,
            self.cropSize.height *比例);

    CGImageRef contextImage = CGImageCreateWithImageInRect([[[self imageWithRotation:self.sourceImage] CGImage],targetFrame);

    如果(contextImage!= NULL){
        finalImage = [UIImage imageWithCGImage:contextImage
                                         规模:self.sourceImage.scale
                                   方向:UIImageOrientationUp];

        CGImageRelease(contextImage);
    }

    返回finalImage;
}


-(UIImage *)imageWithRotation:(UIImage *)image {


    如果(image.imageOrientation == UIImageOrientationUp)返回图像;
    CGAffineTransform transform = CGAffineTransformIdentity;

    开关(image.imageOrientation){
        案例UIImageOrientationDown:
        案例UIImageOrientationDownMirrored:
            transform = CGAffineTransformTranslate(transform,image.size.width,image.size.height);
            转换= CGAffineTransformRotate(transform,M_PI);
            打破;

        案例UIImageOrientationLeft:
        案例UIImageOrientationLeftMirrored:
            transform = CGAffineTransformTranslate(transform,image.size.width,0);
            转换= CGAffineTransformRotate(transform,M_PI_2);
            打破;

        案例UIImageOrientationRight:
        案例UIImageOrientationRightMirrored:
            transform = CGAffineTransformTranslate(transform,0,image.size.height);
            转换= CGAffineTransformRotate(transform,-M_PI_2);
            打破;
        案例UIImageOrientationUp:
        案例UIImageOrientationUpMirrored:
            打破;
    }

    开关(image.imageOrientation){
        案例UIImageOrientationUpMirrored:
        案例UIImageOrientationDownMirrored:
            transform = CGAffineTransformTranslate(transform,image.size.width,0);
            transform = CGAffineTransformScale(transform,-1,1);
            打破;

        案例UIImageOrientationLeftMirrored:
        案例UIImageOrientationRightMirrored:
            transform = CGAffineTransformTranslate(transform,image.size.height,0);
            transform = CGAffineTransformScale(transform,-1,1);
            打破;
        案例UIImageOrientationUp:
        案例UIImageOrientationDown:
        案例UIImageOrientationLeft:
        案例UIImageOrientationRight:
            打破;
    }

    //现在,应用转换将基础CGImage绘制到新的上下文中
    //以上计算得出。
    CGContextRef ctx = CGBitmapContextCreate(NULL,image.size.width,image.size.height,
            CGImageGetBitsPerComponent(image.CGImage),0,
            CGImageGetColorSpace(image.CGImage),
            CGImageGetBitmapInfo(image.CGImage));
    CGContextConcatCTM(ctx,transform);
    开关(image.imageOrientation){
        案例UIImageOrientationLeft:
        案例UIImageOrientationLeftMirrored:
        案例UIImageOrientationRight:
        案例UIImageOrientationRightMirrored:
            // Grr ...
            CGContextDrawImage(ctx,CGRectMake(0,0,image.size.height,image.size.width),image.CGImage);
            打破;

        默认:
            CGContextDrawImage(ctx,CGRectMake(0,0,image.size.width,image.size.height),image.CGImage);
            打破;
    }

    //现在,我们只需根据绘图上下文创建一个新的UIImage
    CGImageRef cgimg = CGBitmapContextCreateImage(ctx);
    UIImage * img = [UIImage imageWithCGImage:cgimg];
    CGContextRelease(ctx);
    CGImageRelease(cgimg);
    返回img;

}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.