Bir UIImage'ı kırpma


209

Bir görüntüyü yeniden boyutlandıran bazı kodlarım var, böylece görüntünün merkezinin ölçeklendirilmiş bir yığınını alabilirim - bunu UIImagealbüm görüntüsünde görülene benzer şekilde bir görüntünün küçük, kare bir temsilini döndürmek için kullanıyorum Fotoğraflar uygulaması. ( UIImageViewAynı sonuçları elde etmek için kırpma modunu ayarlayabileceğimi biliyorum , ancak bu görüntüler bazen görüntüleniyor UIWebViews).

Bu kodda bazı çökmeler fark etmeye başladım ve ben biraz güdük. İki farklı teorim var ve her ikisinin de temelde olup olmadığını merak ediyorum.

Teori 1) Kırpmayı hedef boyutumun bir ekran dışı görüntü bağlamına çizerek elde ederim. Görüntünün orta kısmını istediğimden, görüntü bağlamımın sınırlarından daha büyük bir şeye CGRectaktarılan argümanı ayarladım drawInRect. Bunun Kosher olduğunu umuyordum, ama bunun yerine dokunmamam gereken başka bir hafızayı çizmeye mi çalışıyorum?

Teori 2) Tüm bunları bir arka plan iş parçacığında yapıyorum. Ana iş parçacığı ile sınırlı UIKit bölümleri olduğunu biliyorum. Bir ekran görüntüsüne çizimin bunlardan biri olmadığını umuyordum / umuyordum. Yanlış mıyım?

(Ah, NSImage's drawInRect:fromRect:operation:fraction:yöntemi nasıl özlüyorum .)


Bir kilitlenme teşhisi koymaya çalışıyorsanız uygulamayı hata ayıklayıcı altında çalıştırıyor ve kilitlendiğinde ne olduğunu not almalısınız. Atılan bir istisna olup olmadığını veya sarkan bir işaretçi nedeniyle EXC_BAD_ACCESS alıp almadığınızı bile belirlemediniz. Bunu öğrendikten sonra, teoriler yapmaya başlayabilirsiniz.
benzado

Yeterince adil. Kilitlenme günlüğünde EXC_BAD_ACCESS iletileri olsa da, hata ayıklayıcı altında bu repro'd değil. Bunu gönderdiğimde, uygulamamda aptalca bir hata yaptığım ve birisinin üzerine atlayacağı varsayımıyla çalışıyordum (kırpma yolunu unutmak gibi).
Jablair

Aşağıdakilere değer ve iyi cevaplar için, yine de, NSHipster'da iyi bir teknik ve performans anketi vardır: nshipster.com/image-resizing . İçimdeki saflık CIImage'ı kullanmak istedi, ama pragmatist UIKit / görüntü bağlamını seçti.
Chris Conover

Yanıtlar:


236

2014-05-28 Güncellemesi: Bunu iOS 3 ya da yeni bir şey olduğunda yazdım, şimdiye kadar bunu yapmanın daha iyi yolları olduğundan eminim, muhtemelen yerleşik. Birçok kişinin belirttiği gibi, bu yöntem rotasyonu dikkate almaz; bazı ek cevapları okuyun ve bu soruya verilen yanıtları herkes için yararlı kılmak için biraz yukarı sevgiyi yayın.

Orijinal yanıt:

Aynı soruya verdiğim yanıtı başka bir yere kopyalayacağım / yapıştıracağım:

Bunu yapmak için basit bir sınıf yöntemi yoktur, ancak istenen sonuçları elde etmek için kullanabileceğiniz bir işlev vardır: CGImageCreateWithImageInRect(CGImageRef, CGRect)size yardımcı olacaktır.

İşte kısa bir örnek:

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

13
Öğesi, imageOrientationyukarı dışında bir değere ayarlandığında CGImage, simgesine göre döndürülür UIImageve kırpma dikdörtgeni yanlış olur. Kırpma dikdörtgeni buna göre döndürebilirsiniz, ancak yeni oluşturulan bölüm yukarı UIImageçıkacaktır imageOrientation, böylece kırpılan CGImageiçinde döndürülecektir.
zoul

25
Retina ekranda bu yöntemi kullanarak cropRect genişliğinizi ve yüksekliğinizi iki katına çıkarmanız gerektiğini belirtmek istiyorum. Sadece karşılaştığım bir şey.
petrocket

21
herhangi bir yönde kullanımı yapmak için:[UIImage imageWithCGImage:imageRef scale:largeImage.scale orientation:largeImage.imageOrientation];
Nicos Karalis

3
Retina için destek eklemelisiniz !!
Mário Carvalho

1
@NicosKaralis sadece doğru yöne döndürecek. Ancak görüntüyü kırptığınız alan yine de yanlış olacaktır.
Tim Bodeit

90

Aynı ölçeği ve yönlendirmeyi korurken retina görüntülerini kırpmak için bir UIImage kategorisinde (iOS 4.0 ve üstü) aşağıdaki yöntemi kullanın:

- (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
Burada şartlı olanı öldürebilirdin ve hep birden katlayabilirsin self.scale, değil mi?
Michael Mior

2
Haklısın, Michael, ancak yukarıdaki çözüm retina olmayan cihazlarda biraz daha hızlıdır, çünkü dört çarpma artı bir atama yerine sadece tek bir kontrol yapar. Retina cihazlarda, gerekenden daha fazla tek bir boolean kontrolü olduğundan, kişisel tercih veya hedefe uyma meselesi.
CGee

2
CGImageRelease(imageRef);ARC etkinken kullanmak doğru mu?
CGee


3
Aslında 4 çarpım bir koşulu değerlendirmekten daha hızlı olabilir :) Çarpımlar modern CPU'larda oldukça iyi bir şekilde optimize edilebilirken, koşullar sadece tahmin edilebilir. Ama haklısın, bu bir tercih meselesi. Artan okunabilirlik nedeniyle daha kısa / basit kodu tercih ediyorum.
marsbear

65

Bir UIImage kategorisi oluşturabilir ve istediğiniz yerde kullanabilirsiniz. HitScans'ın yanıtına ve aşağıdaki yorumlara dayanmaktadır.

@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

Bu şekilde kullanabilirsiniz:

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

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

UIImage *croppedImage = [imageToCrop crop:cropRect];

3
Gerekmiyor [[UIScreen mainScreen] scale]sadece olmak self.scale? Görüntünün ölçeği, ekranın ölçeği ile aynı olmayabilir.
Michael Mior

Merhaba, cevabınızı denedim ve No visible @interface for 'UIImage' declares the selector 'crop'projeme .h ve .m kategori dosyalarını koymamı ve kategoriyi kullandığım sınıfta .h dosyasını içe aktarmamı sağlıyor. Herhangi bir fikir?
Ali

Onu düzeltti. UIImage + Crop.h dosyasına yöntem başlığı koyarak özledim.
Ali

Resmi dairesel biçimde kırpmak istiyorum. Böylece sadece dairesel bir yol görebiliriz ve diğer yollar şeffaf kalır.
Alfa

Bundan sonra CGImageCreateWithImageInRect yerine CGImageCreateWithMask veya CGImageCreateWithMaskingColors kullanabilirsiniz
Vilém Kurz

54

Swift 3 sürümü

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

resim açıklamasını buraya girin

Bu köprü fonksiyonu yardımıyla CGRectMake-> CGRect( bu cevaba verilen cevaplar @rob mayoff):

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

Kullanımı:

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

Çıktı:

resim açıklamasını buraya girin


Neden oy kullanıldığından emin değilim, bunun iyi bir cevap olduğunu düşündüm. Düşünebildiğim tek şey, ölçeklendirmeyi işlemediğidir, bu nedenle @ 2x / @ 3x görüntüleriniz varsa ve işlev adlarınız uyuşmuyorsa çalışmaz.
William T.

4
Buna gerek guardilk durumda hat UIImage.CGImagedönüşleri nilve neden kullanımını varzaman letmükemmel çalışıyor.
NoodleOfDeath

Bu doğru, ANCAK, belgeleri cropping(to:)çok dikkatli bir şekilde okuyun . Ortaya çıkan sonuç , kırpıldığı CGImagedaha büyük CGImageolana güçlü bir referans sağlar . Bu nedenle, yalnızca kırpılan görüntüye asmak ve orijinal belgeye ihtiyaç duymuyorsanız, diğer çözümlere bir göz atın.
jsadler

Bu, yönlendirme etiketleri olan görüntülerle çalışmaz. Kırpma bölgesi düzgün şekilde döndürülmüyor.
Max

1
@Max bunun nedeni cgImage'ın yönlendirme desteği olmamasıdır. UIImage yaşıyorsa rightcgImage ccw 90 derece döndürülmelidir, bu nedenle kırpma rektifi de döndürülmelidir
MK Yung

49

İşte imageOrientation özelliğine uyan benim UIImage kırpma uygulaması. Tüm oryantasyonlar iyice test edildi.

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
Uyarı implicit declaration of function 'rad' is invalid in c99değiştirilerek kaldırılabilir: rad (90), rad (-90), rad (-180) -> M_PI_2, -M_PI_2, -_M_PI
Sound Blaster

Ayy üzgünüm. Kaynak snippet'e rad () yardımcı programı işlevi eklendi.
Sergii Rudchenko

contains undefined reference for architecture armv7Kütüphanem eksik mi? CoreGraphics içe aktarıldı.
Bob Spryn

1
@SergiiRudchenko "Tüm yönler iyice test edildi." - Bu, yansıtılmış yönlendirmeleri içeriyor mu?
Tim Bodeit

@BobSpryn Hayır, bir kütüphaneniz eksik değil. Hatanın ne anlama geldiğini açıklayamasam da, SoundBlaster'ın önerdiği gibi rad () öğesinin değiştirilmesi bu hatayı da giderir.
Tim Bodeit

39

Uyarı: tüm bu cevaplar CGImagedestekli bir görüntü nesnesi olduğunu varsayar .

image.CGImageUIImagea tarafından destekleniyorsa nil döndürebilir, CIImagebu görüntüyü a kullanarak oluşturursanız böyle olur CIFilter.

Bu durumda, görüntüyü yeni bir bağlamda çizmeniz ve görüntüyü döndürmeniz ( yavaş ) gerekebilir .

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
Tam da ihtiyacım olan bu, tüm senaryolarda çalışıyor, bu nedenle diğer çözümlerden daha iyi!
David Thompson

2
ilk satırdaki image.size rect.size olmalıdır UIGraphicsBeginImageContextWithOptions (rect.size, false, image.scale);
Brett

2
Teşekkürler Brett, kesinlikle orada. Bu düzeltmeyi eklemek için kodu güncelledim.
colinta

Neden -rect.origin.x sadece rect.origin.x değil?
Saldırgan

2
Çünkü biz kırpıyoruz; başka bir deyişle, 'rect' argümanı "Yeni görüntünün sol üst köşesinden başlamasını istiyorum, diyelim ki [10, 10]" diyor. Bunu yapmak için görüntüyü [10, 10] yeni görüntünün kaynağında olacak şekilde çiziyoruz.
colinta

35

Buradaki cevapların hiçbiri tüm ölçek ve döndürme sorunlarını% 100 doğru şekilde işlemiyor. İşte iOS7 / 8'den bugüne kadar bugüne kadar söylenen her şeyin bir sentezi. UIImage'daki bir kategoriye bir yöntem olarak dahil edilmesi amaçlanmıştır.

- (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
Bu cevap neden daha fazla desteklenmiyor? Yukarıdaki tüm cevapları denedim ve tonlarca sorunla karşılaştım (özellikle UIImage'dan CIImage'a dönüştürme ve uygun dönüşüm verilerini kaybetme). BU BENİM İÇİN ÇALIŞAN TEK SADECE!
Saldırgan

1
Teşekkürler @Aggressor, bunun sizin için çalışmasına sevindim. Cevabım sadece bir ay önce yayınlanmışken, bu cevapların çoğu 5 yıldır burada. Sanırım bu benzer oyların eksikliğini açıklıyor.
awolf

Ben görüntüleri (snapchat nasıl yapar gibi) filtreler tokatlamak için bunu kullanıyorum ve hafif ölçeklendirme sorunları alıyorum. Kodunuzda, bu ölçekleme hatasının nedenini tutabileceğimi önerebileceğiniz bir şey var mı? Kodunuzu kullanan çözümümü buraya gönderdim: stackoverflow.com/questions/23319497/…
Aggressor

çok kullanışlı bir işlev, teşekkürler. herhangi bir ipucu görüntünün orta kısmına odaklanarak kırpmak için ne değiştirilmelidir?
özel

BU CEVAP OLMALIDIR.
at nalı7

17

awolfBenim için çalışan cevabın hızlı versiyonu :

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

Gördüğüm yanıtların çoğu sadece (x, y) için (0, 0) konumuyla ilgilidir. Tamam bu bir durum ama kırpma işlemimin ortalanmasını istiyorum. Anlamak için biraz zamanımı alan, WTF yorumunu izleyen çizgidir.

Dikey yönde çekilen bir görüntüyü ele alalım:

  1. Orijinal görüntü yüksekliği genişliğinden daha yüksek (Woo, şu ana kadar sürpriz yok!)
  2. CGImageCreateWithImageInRect yönteminin kendi dünyasında hayal ettiği görüntü, aslında bir portre değil, bir manzaradır (Bu nedenle, imageWithCGImage yapıcısında yönlendirme bağımsız değişkenini kullanmazsanız, 180 döndürülmüş olarak görünecektir).
  3. Yani, bir manzara olduğunu hayal etmelisiniz, (0, 0) pozisyonu görüntünün sağ üst köşesidir.

Umarım mantıklıdır! Başlamazsa, cropRect'iniz için doğru x, y, genişlik ve yüksekliği seçerken mantığın ters çevrildiğini göreceksiniz.


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

Swift Uzantısı

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'te bir UIImage'ı kesinlik, piksel ölçekleme açısından kırpmak için en iyi çözüm ...:

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
}

Bu işlevi çağırmak için kullanılan talimatlar:

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

Not: Objective-C ile yazılmış ilk kaynak kod ilhamı "Cocoanetics" blogunda bulundu.


3

Aşağıdaki kod snippet'i yardımcı olabilir.

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

Biraz garip görünüyor ama harika çalışıyor ve görüntü yönünü dikkate alıyor:

var image:UIImage = ...

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

1
ama belli ki ölçeği kırar
Sulthan

2

Hızlı 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

İOS9.2SDK'da, çerçeveyi UIView'den UIImage'a dönüştürmek için aşağıdaki yöntemi kullanıyorum

-(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 Güncellemesi ( CIImageuyumluluk)

Maxim'in Yanıtını genişletmek, ancak resminiz de CIImagetemel alıyorsa işe yarar .

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

İşte Noodles cevabına dayalı güncellenmiş bir Swift 3 sürümü

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. I Sadece Kategori işlevine sabitleme. UIImage Kategorisine koy.

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

Diğer çözümlerden memnun kalmadım çünkü ya çok fazla zaman çekiyorlar (gereğinden fazla güç kullanıyorlar) ya da yönelimle ilgili sorunları var. İşte bir UIImage * görüntüsünden ölçekli bir kare kırpılmış görüntü için kullandığım şey.

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

Aşağıdaki yöntemi kullanıyorum.

  -(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 adresine bakın

- (UIImage *) kırpılmışImage {
    CGFloat ölçeği = self.sourceImage.size.width / self.scrollView.contentSize.width;

    UIImage * finalImage = sıfır;
    CGRect targetFrame = CGRectMake ((self.scrollView.contentInset.left + self.scrollView.contentOffset.x) * ölçeği,
            (self.scrollView.contentInset.top + self.scrollView.contentOffset.y) * ölçeği,
            self.cropSize.width * ölçeği,
            self.cropSize.height * ölçeği);

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

    if (contextImage! = NULL) {
        finalImage = [UIImage imageWithCGImage: contextImage
                                         ölçeği: self.sourceImage.scale
                                   yönelimi: UIImageOrientationUp];

        CGImageRelease (contextImage);
    }

    finalImage döndür;
}


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


    if (image.imageOrientation == UIImageOrientationUp) görüntüyü döndürürse;
    CGAffineTransform dönüşümü = CGAffineTransformIdentity;

    switch (image.imageOrientation) {
        case UIImageOrientationDown:
        case UIImageOrientationDownMirrored:
            transform = CGAffineTransformTranslate (dönüştürme, image.size.width, image.size.height);
            transform = CGAffineTransformRotate (dönüşüm, M_PI);
            break;

        case UIImageOrientationLeft:
        case UIImageOrientationLeftMirrored:
            transform = CGAffineTransformTranslate (dönüşüm, görüntü boyutu. genişlik, 0);
            transform = CGAffineTransformRotate (dönüşüm, M_PI_2);
            break;

        case UIImageOrientationRight:
        case UIImageOrientationRightMirrored:
            transform = CGAffineTransformTranslate (dönüşüm, 0, resim.size.height);
            transform = CGAffineTransformRotate (dönüşüm, -M_PI_2);
            break;
        case UIImageOrientationUp:
        case UIImageOrientationUpMirrored:
            break;
    }

    switch (image.imageOrientation) {
        case UIImageOrientationUpMirrored:
        case UIImageOrientationDownMirrored:
            transform = CGAffineTransformTranslate (dönüşüm, görüntü boyutu. genişlik, 0);
            transform = CGAffineTransformScale (dönüşüm, -1, 1);
            break;

        case UIImageOrientationLeftMirrored:
        case UIImageOrientationRightMirrored:
            transform = CGAffineTransformTranslate (dönüşüm, görüntü boyutu. yükseklik, 0);
            transform = CGAffineTransformScale (dönüşüm, -1, 1);
            break;
        case UIImageOrientationUp:
        case UIImageOrientationDown:
        case UIImageOrientationLeft:
        case UIImageOrientationRight:
            break;
    }

    // Şimdi altta yatan CGImage'ı dönüştürmeyi uygulayarak yeni bir bağlama çekiyoruz
    // yukarıda hesaplanmıştır.
    CGContextRef ctx = CGBitmapContextCreate (NULL, image.size.width, image.size.height,
            CGImageGetBitsPerComponent (image.CGImage), 0,
            CGImageGetColorSpace (image.CGImage),
            CGImageGetBitmapInfo (image.CGImage));
    CGContextConcatCTM (ctx, dönüşüm);
    switch (image.imageOrientation) {
        case UIImageOrientationLeft:
        case UIImageOrientationLeftMirrored:
        case UIImageOrientationRight:
        case UIImageOrientationRightMirrored:
            // Grr ...
            CGContextDrawImage (ctx, CGRectMake (0, 0, image.size.height, image.size.width), image.CGImage);
            break;

        varsayılan:
            CGContextDrawImage (ctx, CGRectMake (0, 0, image.size.width, image.size.height), image.CGImage);
            break;
    }

    // Şimdi çizim bağlamından yeni bir UIImage oluşturuyoruz
    CGImageRef cgimg = CGBitmapContextCreateImage (ctx);
    UIImage * img = [UIImage imageWithCGImage: cgimg];
    CGContextRelease (CTX);
    CGImageRelease (cgimg);
    dönüş img;

}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.