UIImage 자르기


209

이미지 크기를 조정하는 코드가있어 이미지 중심의 스케일 된 덩어리를 얻을 수 있습니다.이 이미지를 사용하여 이미지 UIImage의 작은 사각형 이미지 를 가져와 사진 앱. (a를 사용 UIImageView하고 자르기 모드를 조정하여 동일한 결과를 얻을 수는 있지만 이러한 이미지는 때때로에 표시됩니다 UIWebViews).

이 코드에서 충돌이 발생하기 시작했으며 약간 혼란 스러웠습니다. 나는 두 가지 다른 이론을 가지고 있으며 어느 쪽이 기초인지 궁금합니다.

이론 1) 대상 크기의 오프 스크린 이미지 컨텍스트를 그려 자르기를 수행합니다. 이미지의 중앙 부분을 원하기 때문에 CGRect인수를 drawInRect이미지 컨텍스트의 경계보다 큰 것으로 전달했습니다 . 나는 이것이 코셔 (Kosher)라고 기대했지만 대신 만져서는 안되는 다른 메모리를 가져 오려고합니까?

이론 2) 나는이 모든 것을 백그라운드 스레드에서하고 있습니다. 기본 스레드로 제한된 UIKit 부분이 있다는 것을 알고 있습니다. 오프 스크린보기로 그리는 것이 이것들 중 하나가 아니라고 가정 / 기대하고있었습니다. 내가 잘못?

(오, 방법이 그리워요 NSImage's drawInRect:fromRect:operation:fraction:.)


충돌을 진단하려는 경우 디버거에서 앱을 실행하고 충돌시 발생하는 상황을 기록해야합니다. 예외가 발생하거나 매달려있는 포인터로 인해 EXC_BAD_ACCESS를 얻는 지조차 식별하지 못했습니다. 일단 당신이 그것을 알고 나면 이론을 만들기 시작할 수 있습니다.
benzado

그럴 수 있지. 크래시 로그에 EXC_BAD_ACCESS 메시지가 있지만 디버거에서 이것을 재현하지 않았습니다. 내가 이것을 게시했을 때, 나는 구현에서 바보 같은 실수를 저지르고 누군가 클리핑 패스를 잊어 버리는 것처럼 누군가 실수로 뛰어 들었다는 가정하에 일하고있었습니다.
Jablair

무엇, 그 NSHipster에 대한 기술 및 성능의 좋은 조사가에도 불구하고 아래에의 가치가 좋은 답변 : nshipster.com/image-resizing . 내 순수 주의자는 CIImage를 사용하고 싶었지만 실용 주의자는 UIKit / 이미지 컨텍스트를 선택했습니다.
Chris Conover

답변:


236

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

13
imageOrientation가 위로 설정되어 있으면에 CGImage대해가 회전되고 UIImage자르기 사각형이 잘못됩니다. 그에 따라 자르기 사각형을 회전 할 수 있지만 새로 만든 자르기 사각형 UIImageimageOrientation위로 올라와 자르기 사각형 이 그 CGImage안에서 회전합니다.
zoul

25
Retina 디스플레이 에서이 방법을 사용하여 cropRect 너비와 높이를 두 배로 늘려야한다고 지적하고 싶습니다. 내가 만난 것.
petrocket

21
어떤 방향으로도 사용할 수 있습니다 :[UIImage imageWithCGImage:imageRef scale:largeImage.scale orientation:largeImage.imageOrientation];
Nicos Karalis

3
Retina에 대한 지원을 추가해야합니다 !!
Mário Carvalho

1
올바른 방향으로 만 회전시키는 @NicosKaralis 그러나 이미지에서 자르는 영역은 여전히 ​​잘못됩니다.
Tim Bodeit

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

2
네 말이 맞아, 그러나 위의 솔루션은 4 개의 곱셈과 대입 대신에 단 하나의 검사 만 수행하기 때문에 비 레티 나 장치에서 조금 더 빠르다고 생각합니다. 망막 장치에서는 필요 이상의 단일 부울 검사이므로 개인 취향 또는 목표 맞추기의 문제입니다.
CGee

2
CGImageRelease(imageRef);ARC가 활성화 된 상태 에서 사용 하는 것이 맞 습니까?
CGee


3
실제로 4 개의 곱셈은 하나의 조건을 평가하는 것보다 빠를 수 있습니다. 그러나 당신이 옳습니다. 그것은 선호의 문제입니다. 가독성이 향상되어 더 짧고 간단한 코드를 선호합니다.
marsbear

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

안녕하세요, 귀하의 답변을 시도했는데 No visible @interface for 'UIImage' declares the selector 'crop'.h 및 .m 범주 파일을 프로젝트에 넣고 범주를 사용하는 클래스에서 .h를 가져 왔지만 나 에게줍니다 . 어떤 생각?
Ali

고쳤다. UIImage + Crop.h 파일에 메소드 헤더를 넣지 못했습니다.
Ali

이미지를 원형으로 자르고 싶습니다. 원형 경로 만 볼 수 있고 다른 경로는 투명하게 유지됩니다.
Alfa

당신은 CGImageCreateWithMask 또는 CGImageCreateWithMaskingColors 대신 CGImageCreateWithImageInRect 사용할 수 있습니다보다
빌렘 커즈

54

스위프트 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 이미지가 있고 함수 이름이 일치하지 않으면 작동하지 않는다는 것입니다.
William T.

4
당신은 할 필요가 guard첫 번째 경우의 라인 UIImage.CGImage반환 nil왜 사용을 var할 때 let완벽하게 작동합니다.
NoodleOfDeath

그러나 이것은 문서를 cropping(to:)매우주의 깊게 읽으십시오 . 결과 는 자른 CGImage큰 부분 CGImage을 강력하게 참조합니다 . 그래서 당신이 원하는 경우 에만 자른 이미지에 걸고 원본에 대한 필요가 없습니다, 다른 솔루션에서보세요.
jsadler

방향 태그가있는 이미지에는 작동하지 않습니다. 자르기 영역이 제대로 회전하지 않습니다.
Max

1
@Max 이것은 cgImage에 방향 지원이 없기 때문입니다. UIImage가 있으면 rightcgImage를 90도 회전시켜야하므로 자르기 사각형도 회전해야합니다
MK Yung

49

다음은 imageOrientation 속성을 따르는 UIImage 자르기 구현입니다. 모든 오리엔테이션을 철저히 테스트했습니다.

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-> M_PI_2, -M_PI_2, -_M_PI RAD (90), 라드 (-90), 라드 (-180) 교체함으로써 제거 될 수있다
사운드 블라스터

앗 미안 해요. 소스 스 니펫에 rad () 유틸리티 함수를 추가했습니다.
Sergii Rudchenko

contains undefined reference for architecture armv7도서관이 없습니까? CoreGraphics를 가져옵니다.
밥 Spryn

1
@SergiiRudchenko "모든 오리엔테이션이 철저히 테스트되었습니다." -여기에는 미러링 된 방향이 포함됩니까?
Tim Bodeit

@BobSpryn 아니요 라이브러리가 없습니다. 오류의 의미를 설명 할 수는 없지만 SoundBlaster가 제안한 것처럼 rad ()를 대체하면이 오류도 수정됩니다.
Tim Bodeit

39

헤딩 :이 모든 답변은 백업 CGImage이미지 객체를 가정 합니다.

image.CGImage이 경우, nil을 반환 할 수 있습니다 UIImagea로 백업됩니다 CIImage당신은을 사용하여 이미지를 만든 경우 경우가 것이다, 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
이것은 내가 필요한 것이므로 모든 시나리오에서 작동하므로 다른 솔루션보다 우수합니다!
David Thompson

2
첫 번째 줄의 image.size는 rect.size 여야합니다. UIGraphicsBeginImageContextWithOptions (rect.size, false, image.scale);
Brett

2
Brett에게 감사합니다. 이 수정 프로그램을 포함하도록 코드를 업데이트했습니다.
colinta

왜 rect.origin.x가 아닌 -rect.origin.x입니까?
침략자 September

2
우리는 자르기 때문에; 다시 말해, 'rect'arg는 "새 이미지의 왼쪽 상단을 시작합니다. 예를 들어 [10, 10]"입니다. 이를 위해 [10, 10]이 새로운 이미지의 원점이되도록 이미지를 그립니다.
colinta

35

여기의 답변 중 어느 것도 모든 스케일 및 회전 문제를 100 % 올바르게 처리하지 못합니다. 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/…
Aggressor

매우 유용한 기능입니다. 감사합니다. 이미지의 중앙 부분에 초점을 맞추기 위해 수정해야 할 팁이 있습니까?
개인

이것은 답변이되어야합니다.
horseshoe7

17

awolf나를 위해 일한의 답변 스위프트 버전 :

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 생성자에서 orientation 인수를 사용하지 않으면 180 회전으로 표시됩니다).
  3. 이미지가 오른쪽 상단 인 (0, 0) 위치 인 풍경이라고 상상해보십시오.

이해가 되길 바랍니다! 그렇지 않으면 다른 값을 시도하여 cropRect에 적합한 x, y, 너비 및 높이를 선택할 때 논리가 반전된다는 것을 알 수 있습니다.


8

swift3

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

참고 : Objective-C로 작성된 초기 소스 코드 영감은 "Cocoanetics"블로그에서 찾을 수 있습니다.


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의 답변에서 확장 되지만 이미지가 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 scale = 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);

    if (contextImage! = NULL) {
        finalImage = [UIImage imageWithCGImage : contextImage
                                         scale : self.sourceImage.scale
                                   orientation : UIImageOrientationUp];

        CGImageRelease (contextImage);
    }

    finalImage를 반환;
}


-(UIImage *) imageWithRotation : (UIImage *) 이미지 {


    if (image.imageOrientation == UIImageOrientationUp) 이미지를 반환합니다;
    CGAffineTransform 변환 = CGAffineTransformIdentity;

    스위치 (image.imageOrientation) {
        case UIImageOrientationDown :
        case UIImageOrientationDownMirrored :
            변환 = CGAffineTransformTranslate (변환, 이미지 크기, 너비, 이미지 크기);
            변환 = CGAffineTransformRotate (변환, M_PI);
            단절;

        case UIImageOrientationLeft :
        case UIImageOrientationLeftMirrored :
            변환 = CGAffineTransformTranslate (변환, image.size.width, 0);
            변환 = CGAffineTransformRotate (변환, M_PI_2);
            단절;

        case UIImageOrientationRight :
        case UIImageOrientationRightMirrored :
            변환 = CGAffineTransformTranslate (변환, 0, image.size.height);
            변환 = CGAffineTransformRotate (변환, -M_PI_2);
            단절;
        case UIImageOrientationUp :
        case UIImageOrientationUp 미러 :
            단절;
    }

    스위치 (image.imageOrientation) {
        case UIImageOrientationUp 미러 :
        case UIImageOrientationDownMirrored :
            변환 = CGAffineTransformTranslate (변환, image.size.width, 0);
            변환 = CGAffineTransformScale (변환, -1, 1);
            단절;

        case UIImageOrientationLeftMirrored :
        case UIImageOrientationRightMirrored :
            변환 = CGAffineTransformTranslate (변환, 이미지 크기. 높이, 0);
            변환 = CGAffineTransformScale (변환, -1, 1);
            단절;
        case UIImageOrientationUp :
        case UIImageOrientationDown :
        case UIImageOrientationLeft :
        case UIImageOrientationRight :
            단절;
    }

    // 이제 기본 CGImage를 새로운 컨텍스트에 그리면서 변형을 적용합니다.
    // 위에서 계산했습니다.
    CGContextRef ctx = CGBitmapContextCreate (NULL, image.size.width, image.size.height,
            CGImageGetBitsPerComponent (image.CGImage), 0,
            CGImageGetColorSpace (image.CGImage),
            CGImageGetBitmapInfo (image.CGImage));
    CGContextConcatCTM (ctx, 변환);
    스위치 (image.imageOrientation) {
        case UIImageOrientationLeft :
        case UIImageOrientationLeftMirrored :
        case UIImageOrientationRight :
        case 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를 반환;

}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.