UIImageのトリミング


209

画像の中心のスケーリングされたチャンクを取得できるように、画像のサイズを変更するコードをいくつか持っています-これを使用して、画像UIImageの小さな正方形の表現を取得し、写真アプリ。(私UIImageViewは同じ結果を達成するためにa を使用してトリミングモードを調整できることを知っていますが、これらの画像は時々に表示されますUIWebViews)。

このコードのいくつかのクラッシュに気づき始めて、少し困惑しています。私は2つの異なる理論を持っているので、どちらがベースにあるのか疑問に思っています。

理論1)ターゲットサイズのオフスクリーンイメージコンテキストに描画することでトリミングを実現します。画像の中央部分が必要なので、CGRect渡された引数drawInRectを、画像コンテキストの境界よりも大きいものに設定します。私はこれがコーシャであることを望んでいたが、代わりに私が触れてはならない他の記憶を上書きしようとしているのだろうか?

理論2)私は、これらすべてをバックグラウンドスレッドで実行しています。メインスレッドに制限されているUIKitの部分があることを知っています。オフスクリーンビューへの描画がこれらの1つではないことを想定していたのです。私が間違っている?

(ああ、どうやってNSImage's drawInRect:fromRect:operation:fraction:メソッドを逃したか。)


クラッシュを診断しようとしている場合は、デバッガーの下でアプリを実行し、クラッシュしたときに何が起こるかをメモしておく必要があります。スローされている例外があるか、または宙ぶらりんのポインターが原因でEXC_BAD_ACCESSを取得しているかどうかも特定できません。それがわかったら、理論の作成を開始できます。
ベンザド2008年

けっこうだ。デバッガーでこれを再現していませんが、クラッシュログにEXC_BAD_ACCESSメッセージがあります。私がこれを投稿したとき、私は自分の実装で愚かな間違いを犯し、誰かがそれに飛びついてしまう(クリッピングパスを忘れるなど)という想定の下で作業していました。
Jablair 2008年

価値があることと、以下の適切な回答があるにもかかわらず、NSHipsterのテクニックとパフォーマンスについての良い調査があります:nshipster.com/image-resizing。私の純粋主義者はCIImageを使用したかったのですが、実用主義者はUIKit /画像コンテキストを選択しました。
Chris Conover、2015年

回答:


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がup以外に設定されている場合、はCGImageを基準にして回転されUIImage、トリミングする四角形は正しくありません。それに応じてトリミング四角形を回転させることができますが、新しく作成された長方形UIImageimageOrientation上になるため、トリミングCGImageされた四角形はその中で回転します。
zoul

25
Retinaディスプレイでは、この方法を使用して、cropRectの幅と高さを2倍にする必要があることを指摘しておきます。ちょうど私が遭遇した何か。
petrocket '14年

21
任意の方向で使用できるようにするには:[UIImage imageWithCGImage:imageRef scale:largeImage.scale orientation:largeImage.imageOrientation];
Nicos Karalis

3
Retinaのサポートを追加する必要があります!!
マリオカルバーリョ

1
正しい向きに回転させるだけの@NicosKaralis。ただし、画像からトリミングしている領域は、まだ間違っています。
Tim Bodeit 2013

90

同じスケールと方向を維持しながらRetinaイメージをトリミングするには、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 2013

2
CGImageRelease(imageRef);ARCを有効にして使用することは正しいですか?
CGee 2013


3
実際、4つの乗算は1つの条件を評価するよりも高速かもしれません:)乗算は最新のCPUでかなり適切に最適化できますが、条件は予測のみできます。しかし、あなたは正しい、それは好みの問題です。読みやすさが向上したため、私はより短い/より単純なコードを好みます。
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

こんにちは、私はあなたの答えを試してみましたが、それは私を与えるNo visible @interface for 'UIImage' declares the selector 'crop'、私は私のプロジェクトでの.hと.mファイルカテゴリファイルを入れて、私は、カテゴリを使用しているクラスでの.hを輸入していても。何か案が?
アリ

修正しました。UIImage + Crop.hファイルにメソッドヘッダーを配置していません。
アリ

画像を円形にトリミングしたい。円形のパスのみが表示され、他のパスは透明のままです。
Alfa

あなたは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と、なぜ完全varlet機能するときに使用する必要があるかを示します。
NoodleOfDeath 2016年

これは正しいですが、ドキュメントをcropping(to:)非常に注意深く読んでください。結果CGImageは、CGImage切り取られた大きい方への強い参照を保持します。だから、あなたがしたい場合のみ、トリミングされた画像にハングアップし、オリジナルを必要としない、他のソリューションを見てみましょう。
jsadler 2017

これは、方向タグのある画像では機能しません。トリミング領域が適切に回転されません。
最大

1
@Maxこれは、cgImageが方向をサポートしていないためです。UIImageの場合right、cgImageを反時計回りに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)、RAD(-90)、RAD(-180):置換することによって除去することができる
のSound Blaster

おっと、ごめんなさい。ソーススニペットにrad()ユーティリティ関数を追加しました。
Sergii Rudchenko 2013

contains undefined reference for architecture armv7ライブラリがありませんか?CoreGraphicsがインポートされます。
Bob Spryn 2013年

1
@SergiiRudchenko「すべてのオリエンテーションは徹底的にテストされました。」-これには、ミラーリングされた向きが含まれますか?
Tim Bodeit 2013

@BobSprynいいえライブラリを見逃していません。エラーの意味を説明することはできませんが、SoundBlasterが提案するようにrad()を置き換えると、このエラーも修正されます。
Tim Bodeit 2013

39

ヘッドアップ:これらすべての答えは、CGImage-backed画像オブジェクトを想定しています。

image.CGImage場合は、nilを返すことができますUIImageによって支えられてCIImage、あなたが使用してこのイメージを作成した場合ケースであろう、CIFilter

その場合、新しいコンテキストで画像を描画し、その画像を返す必要があります(遅い)。

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);
ブレット

2
ブレット、ありがとうございます。この修正を含めるようにコードを更新しました。
コリンタ2014年

なぜrect.origin.xだけではなく-rect.origin.xなのですか?
アグレッサー

2
トリミングしているので、言い換えると、 'rect'引数は「新しい画像の左上を[10、10]などから始めたい」と言っています。そのためには、[10、10]が新しい画像の原点になるように画像を描画します。
コリンタ2014

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への変換と適切な変換データの損失)。これは私にとって有効な唯一のものです!
アグレッサー、2014

1
@Aggressor、ありがとうございます。私の回答は1か月前に投稿されましたが、これらの回答の多くは5年間ここにあります。比較可能な賛成票がないことを説明していると思います。
ウルフ

これを使用して(snapchatのように)画像全体でフィルターをスワイプし、わずかなスケーリングの問題を抱えています。あなたのコードに、このスケーリングエラーの原因を保持している可能性があると思われることを提案できるものはありますか?私はここにあなたのコードを使用して私の解決策を掲載: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)の位置のみを扱います。それは1つのケースですが、トリミング操作を中央に配置したいのですが。私が理解するのに少し時間がかかったのは、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
しかし、それは明らかにスケールを壊します
スルタン

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互換性)

マキシムの回答を拡張したものですが、画像が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);

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

        CGImageRelease(contextImage);
    }

    finalImageを返します。
}


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


    if(image.imageOrientation == UIImageOrientationUp)画像を返す;
    CGAffineTransform変換= CGAffineTransformIdentity;

    スイッチ(image.imageOrientation){
        ケースUIImageOrientationDown:
        ケースUIImageOrientationDownMirrored:
            transform = CGAffineTransformTranslate(transform、image.size.width、image.size.height);
            transform = CGAffineTransformRotate(transform、M_PI);
            ブレーク;

        ケースUIImageOrientationLeft:
        ケースUIImageOrientationLeftMirrored:
            transform = CGAffineTransformTranslate(transform、image.size.width、0);
            transform = CGAffineTransformRotate(transform、M_PI_2);
            ブレーク;

        ケースUIImageOrientationRight:
        ケースUIImageOrientationRightMirrored:
            transform = CGAffineTransformTranslate(transform、0、image.size.height);
            transform = 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を返す;

}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.