Memotong UIImage

209

Saya punya beberapa kode yang mengubah ukuran gambar sehingga saya bisa mendapatkan potongan skala dari pusat gambar - saya menggunakan ini untuk mengambil UIImagedan mengembalikan representasi persegi kecil dari gambar, mirip dengan apa yang terlihat dalam tampilan album dari aplikasi Foto. (Saya tahu saya bisa menggunakan UIImageViewdan menyesuaikan mode krop untuk mencapai hasil yang sama, tetapi gambar-gambar ini kadang-kadang ditampilkan di UIWebViews).

Saya sudah mulai memperhatikan beberapa crash dalam kode ini dan saya agak bingung. Saya punya dua teori berbeda dan saya bertanya-tanya apakah keduanya ada di pangkalan.

Teori 1) Saya mencapai pemangkasan dengan menggambar ke dalam konteks gambar di luar layar dari ukuran target saya. Karena saya ingin bagian tengah gambar, saya mengatur CGRectargumen yang diteruskandrawInRect ke sesuatu yang lebih besar daripada batas konteks gambar saya. Saya berharap ini adalah halal, tetapi apakah saya malah mencoba mengambil alih memori lain yang seharusnya tidak saya sentuh?

Teori 2) Saya melakukan semua ini di utas latar belakang. Saya tahu ada bagian dari UIKit yang terbatas pada utas utama. Saya berasumsi / berharap bahwa menggambar ke tampilan offscreen bukan salah satunya. Apakah aku salah?

(Oh, betapa aku merindukan NSImage's drawInRect:fromRect:operation:fraction:metode.)

Jablair
sumber
Jika Anda mencoba mendiagnosis crash, Anda harus menjalankan aplikasi di bawah debugger dan mencatat apa yang terjadi ketika crash. Anda bahkan belum mengidentifikasi jika ada pengecualian yang dilemparkan atau Anda mendapatkan EXC_BAD_ACCESS karena penunjuk yang menggantung. Setelah Anda tahu itu, maka Anda bisa mulai membuat teori.
benzado
Cukup adil. Saya belum repro ini di bawah debugger, meskipun saya punya pesan EXC_BAD_ACCESS di log kerusakan. Ketika saya memposting ini, saya bekerja di bawah asumsi bahwa saya telah membuat kesalahan bodoh dalam implementasi saya dan seseorang akan melompat di atasnya (seperti melupakan jalan kliping).
Jablair
Untuk apa nilainya dan jawaban yang baik di bawah meskipun demikian, ada survei teknik dan kinerja yang baik di NSHipster: nshipster.com/image-resizing . Purist di dalam saya ingin menggunakan CIImage, tetapi pragmatis memilih UIKit / konteks gambar.
Chris Conover

Jawaban:

236

Pembaruan 2014-05-28: Saya menulis ini ketika iOS 3 atau lebih adalah hal baru yang panas, saya yakin ada cara yang lebih baik untuk melakukan ini sekarang, mungkin built-in. Seperti yang banyak orang sebutkan, metode ini tidak memperhitungkan rotasi; baca beberapa jawaban tambahan dan sebarkan cinta upvote sekitar untuk menjaga respon terhadap pertanyaan ini bermanfaat bagi semua orang.

Tanggapan asli:

Saya akan menyalin / menempelkan respons saya ke pertanyaan yang sama di tempat lain:

Tidak ada metode kelas sederhana untuk melakukan ini, tetapi ada fungsi yang dapat Anda gunakan untuk mendapatkan hasil yang diinginkan: CGImageCreateWithImageInRect(CGImageRef, CGRect)akan membantu Anda.

Berikut ini contoh singkat menggunakannya:

CGImageRef imageRef = CGImageCreateWithImageInRect([largeImage CGImage], cropRect);
// or use the UIImage wherever you like
[UIImageView setImage:[UIImage imageWithCGImage:imageRef]]; 
CGImageRelease(imageRef);
HitScan
sumber
13
Ketika imageOrientationdiatur ke apa pun kecuali ke atas, CGImagediputar dengan memperhatikan UIImagedan persegi panjang pemangkasan akan salah. Anda dapat memutar persegi panjang pemangkasan sesuai, tetapi yang baru dibuat UIImageakan imageOrientationnaik, sehingga dipotong CGImageakan diputar di dalamnya.
zoul
25
Saya ingin menunjukkan bahwa pada tampilan retina Anda perlu menggandakan lebar & tinggi cropRect Anda menggunakan metode ini. Hanya sesuatu yang saya temui.
petrocket
21
untuk membuatnya berfungsi dalam setiap orientasi gunakan:[UIImage imageWithCGImage:imageRef scale:largeImage.scale orientation:largeImage.imageOrientation];
Nicos Karalis
3
Anda harus menambahkan dukungan untuk Retina !!
Mário Carvalho
1
@NicosKaralis yang hanya akan memutarnya ke arah yang benar. Namun area, yang Anda potong dari gambar akan tetap salah.
Tim Bodeit
90

Untuk memotong gambar retina dengan tetap menjaga skala dan orientasi yang sama, gunakan metode berikut dalam kategori UIImage (iOS 4.0 dan lebih tinggi):

- (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;
}
Arne
sumber
14
Anda bisa saja membunuh kondisional di sini dan selalu berlipat ganda self.scale, bukan?
Michael Mior
2
Anda benar, Michael, tetapi saya pikir solusi di atas sedikit lebih cepat pada perangkat non-retina karena hanya melakukan pemeriksaan tunggal alih-alih empat perkalian plus tugas. Pada perangkat retina, ini hanya satu boolean cek lebih dari yang diperlukan, jadi ini adalah pertanyaan tentang preferensi pribadi atau kecocokan target.
CGee
2
Apakah benar menggunakan CGImageRelease(imageRef);ARC diaktifkan?
CGee
3
@ Dschee Ya. Lihat stackoverflow.com/questions/7800174/…
Klaas
3
Sebenarnya 4 perkalian mungkin lebih cepat daripada mengevaluasi satu kondisi :) Perkalian dapat dioptimalkan dengan cukup baik pada CPU modern sedangkan kondisi hanya dapat diprediksi. Tapi Anda benar, ini masalah preferensi. Saya lebih suka kode yang lebih pendek / lebih sederhana karena peningkatan keterbacaan.
Marsars
65

Anda dapat membuat kategori UIImage dan menggunakannya di mana pun Anda butuhkan. Berdasarkan tanggapan HitScans dan komentar di bawahnya.

@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

Anda dapat menggunakannya dengan cara ini:

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

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

UIImage *croppedImage = [imageToCrop crop:cropRect];
Vilém Kurz
sumber
3
Bukankah seharusnya [[UIScreen mainScreen] scale]begitu self.scale? Skala gambar mungkin tidak sama dengan skala layar.
Michael Mior
Hai, saya mencoba jawaban Anda dan itu memberi saya No visible @interface for 'UIImage' declares the selector 'crop'meskipun saya meletakkan file kategori .h dan .m di proyek saya dan mengimpor .h di kelas saya menggunakan kategori. Ada ide?
Ali
Memperbaikinya. Saya merindukan menempatkan metode header di file UIImage + Crop.h.
Ali
Saya ingin memotong gambar dalam bentuk lingkaran. Sehingga kita bisa melihat hanya jalur melingkar dan jalur lainnya tetap transparan.
Alfa
Daripada Anda dapat menggunakan CGImageCreateWithMask atau CGImageCreateWithMaskingColors, bukan CGImageCreateWithImageInRect
Vilém Kurz
54

Versi 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

masukkan deskripsi gambar di sini

dengan bantuan fungsi jembatan ini CGRectMake -> CGRect(kredit untuk jawaban ini dijawab oleh @rob mayoff):

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

Penggunaannya adalah:

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

Keluaran:

masukkan deskripsi gambar di sini

Maxim Shoustin
sumber
Tidak yakin mengapa itu tidak dipilih, saya pikir itu adalah jawaban yang bagus. Satu-satunya hal yang dapat saya pikirkan adalah bahwa ia tidak menangani penskalaan sehingga tidak akan berfungsi jika Anda memiliki gambar @ 2x / @ 3x dan nama fungsi Anda tidak cocok.
William T.
4
Anda perlu ke guardbaris pertama jika UIImage.CGImagekembali nildan mengapa digunakan varsaat letbekerja dengan sempurna.
NoodleOfDeath
Ini benar, NAMUN, baca dokumen dengan cropping(to:)sangat hati-hati. Hasilnya CGImagememegang referensi kuat ke yang lebih besar CGImagedari yang dipotong. Jadi, jika Anda ingin hanya berpegang pada gambar yang dipangkas dan tidak membutuhkan yang asli, lihat solusi lainnya.
jsadler
Ini tidak berfungsi dengan gambar yang memiliki tag orientasi. Wilayah krop tidak diputar dengan benar.
Maks.
1
@ Max ini karena cgImage tidak memiliki dukungan orientasi. Jika UIImage mengalami hal ini rightmaka cgImage harus diputar sebanyak 90 derajat, maka crop rect harus diputar juga
MK Yung
49

Ini adalah implementasi crop UIImage saya yang mematuhi properti imageOrientation. Semua orientasi diuji secara menyeluruh.

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;
}
Sergii Rudchenko
sumber
7
Peringatan implicit declaration of function 'rad' is invalid in c99dapat dihapus dengan mengganti: rad (90), rad (-90), rad (-180) -> M_PI_2, -M_PI_2, -_M_PI
Sound Blaster
Ups, maaf. Menambahkan fungsi utilitas rad () ke cuplikan sumber.
Sergii Rudchenko
contains undefined reference for architecture armv7Apakah saya kehilangan perpustakaan? CoreGraphics diimpor.
Bob Spryn
1
@SergiiRudchenko "Semua orientasi diuji secara menyeluruh." - Apakah ini termasuk orientasi cermin?
Tim Bodeit
@ BobSpryn Tidak, Anda tidak ketinggalan perpustakaan. Meskipun saya tidak dapat menjelaskan apa artinya kesalahan itu, penggantian rad (), seperti yang disarankan SoundBlaster, juga memperbaiki kesalahan ini.
Tim Bodeit
39

Kepala: semua jawaban ini menganggap CGImageobjek gambar yang dikembalikan.

image.CGImagedapat mengembalikan nol, jika UIImagedidukung oleh CIImage, yang akan terjadi jika Anda membuat gambar ini menggunakan a CIFilter.

Dalam hal ini, Anda mungkin harus menggambar gambar dalam konteks baru, dan mengembalikan gambar itu ( lambat ).

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;
}
colinta
sumber
5
Inilah yang saya butuhkan, bekerja di semua skenario karena itu lebih baik daripada solusi lainnya!
David Thompson
2
image.ukuran pada baris pertama harus rect.size UIGraphicsBeginImageContextWithOptions (rect.size, false, image.scale);
Brett
2
Terima kasih Brett, pasti di sana. Saya memperbarui kode untuk menyertakan perbaikan ini.
colinta
Mengapa -rror.origin.x bukan hanya rect.origin.x?
Aggressor
2
Karena kita menanam; dengan kata lain, argumen 'rect' mengatakan "Saya ingin bagian kiri atas gambar baru dimulai, katakanlah, [10, 10]". Untuk melakukan itu kita menggambar gambar sehingga [10, 10] adalah asal gambar baru.
colinta
35

Tidak ada jawaban di sini yang menangani semua masalah skala dan rotasi 100% dengan benar. Berikut adalah sintesis dari semua yang dikatakan sejauh ini, terbaru pada iOS7 / 8. Ini dimaksudkan untuk dimasukkan sebagai metode dalam kategori di 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;
}
seekor serigala
sumber
1
Mengapa jawaban ini tidak lebih dipilih? Saya mencoba semua jawaban di atas dan mengalami banyak masalah (terutama mengkonversi dari UIImage ke CIImage dan kehilangan data transformasi yang tepat). INI HANYA SATU YANG BEKERJA BAGI SAYA!
Aggressor
1
Terima kasih @Aggressor, senang ini berhasil untuk Anda. Jawaban saya baru diposting sebulan yang lalu sedangkan banyak dari jawaban ini telah ada di sini selama 5 tahun. Saya menduga itu menjelaskan kurangnya jumlah suara yang sebanding.
awolf
Saya menggunakan ini untuk menggesek filter di seluruh gambar (seperti bagaimana snapchat) dan saya mendapatkan sedikit masalah skala. Apakah ada sesuatu dalam kode Anda yang dapat Anda sarankan agar saya perhatikan yang mungkin menjadi penyebab kesalahan penskalaan ini? Saya memposting solusi saya yang menggunakan kode Anda di sini: stackoverflow.com/questions/23319497/…
Aggressor
fungsi yang sangat berguna, terima kasih. ada tips apa yang harus dimodifikasi untuk memotong fokus pada bagian tengah gambar?
pribadi
INI HARUS MENJAWAB JAWABANNYA.
horseshoe7
17

awolfJawaban versi cepat , yang bekerja untuk saya:

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
    }
}
Mark Leonard
sumber
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);

Sebagian besar respons yang saya lihat hanya berkaitan dengan posisi (0, 0) untuk (x, y). Ok itu satu kasus tetapi saya ingin operasi tanam saya terpusat. Apa yang membuat saya perlu waktu untuk mencari tahu adalah garis mengikuti komentar WTF.

Mari kita ambil contoh gambar yang diambil dengan orientasi potret:

  1. Tinggi gambar asli lebih tinggi dari lebarnya (Woo, sejauh ini tidak mengejutkan!)
  2. Gambar yang dibayangkan metode CGImageCreateWithImageInRect di dunianya sendiri sebenarnya bukan potret, melainkan lansekap (Itulah sebabnya mengapa jika Anda tidak menggunakan argumen orientasi dalam konstruktor imageWithCGImage, gambar itu akan ditampilkan sebagai 180 diputar).
  3. Jadi, Anda harus membayangkan bahwa itu adalah lanskap, posisi (0, 0) menjadi sudut kanan atas gambar.

Semoga masuk akal! Jika tidak, coba nilai yang berbeda Anda akan melihat bahwa logika terbalik ketika harus memilih x, y, lebar, dan tinggi yang tepat untuk cropRect Anda.

Yordania
sumber
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)
    }
}
neoneye
sumber
7

Ekstensi cepat

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
    }
}
Epic Byte
sumber
4

Solusi terbaik untuk memotong UIImage di Swift , dalam hal presisi, penskalaan piksel ...:

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
}

Instruksi yang digunakan untuk memanggil fungsi ini:

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

Catatan: inspirasi kode sumber awal yang ditulis dalam Objective-C telah ditemukan di blog "Cocoanetics".

Raja-Penyihir
sumber
3

Cuplikan kode di bawah ini mungkin membantu.

import UIKit

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

Terlihat sedikit aneh tapi berfungsi dengan baik dan mempertimbangkan orientasi gambar:

var image:UIImage = ...

let img = CIImage(image: image)!.imageByCroppingToRect(rect)
image = UIImage(CIImage: img, scale: 1, orientation: image.imageOrientation)
MuniekMg
sumber
1
tetapi jelas merusak skala
Sulthan
2

Swift 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
    }
}
Huync
sumber
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;
}
Keemasan
sumber
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;
}
Bhushan_pawar
sumber
1

Di iOS9.2SDK, saya menggunakan metode di bawah ini untuk mengkonversi frame dari UIView ke 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;
}
pengguna5176302
sumber
1

Pembaruan Swift 2.0 ( CIImagekompatibilitas)

Memperluas Jawaban Maxim tetapi berfungsi jika gambar Anda juga CIImagedidasarkan.

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
   }
}
NoodleOfDeath
sumber
1

Berikut ini adalah versi Swift 3 yang diperbarui berdasarkan jawaban Mie

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
}
voidref
sumber
1

Ikuti Jawaban dari @Arne. Saya Hanya memperbaiki ke fungsi Kategori. letakkan di Kategori 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;
}
Linh Nguyen
sumber
0

Saya tidak puas dengan solusi lain karena mereka mengambil beberapa waktu (menggunakan lebih banyak daya daripada yang diperlukan) atau memiliki masalah dengan orientasi. Berikut adalah apa yang saya gunakan untuk croppedImage persegi berskala dari gambar UIImage *.

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();
Matthieu Rouif
sumber
0

Saya menggunakan metode di bawah ini.

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

}

pengguna5176302
sumber
0

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

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

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

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

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

        CGImageRelease (contextImage);
    }

    mengembalikan finalImage;
}


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


    if (image.imageOrientation == UIImageOrientationUp) mengembalikan gambar;
    Transformasi CGAffineTransform = CGAffineTransformIdentity;

    switch (image.imageOrientation) {
        case UIImageOrientationDown:
        case UIImageOrientationDownMirrored:
            transform = CGAffineTransformTranslate (transform, image.size.width, image.size.height);
            transform = CGAffineTransformRotate (transform, M_PI);
            istirahat;

        case UIImageOrientationLeft:
        case UIImageOrientationLeftMirrored:
            transform = CGAffineTransformTranslate (transform, image.size.width, 0);
            transform = CGAffineTransformRotate (transform, M_PI_2);
            istirahat;

        case UIImageOrientationRight:
        case UIImageOrientationRightMirrored:
            transform = CGAffineTransformTranslate (transform, 0, image.size.height);
            transform = CGAffineTransformRotate (transform, -M_PI_2);
            istirahat;
        case UIImageOrientationUp:
        case UIImageOrientationUpMirrored:
            istirahat;
    }

    switch (image.imageOrientation) {
        case UIImageOrientationUpMirrored:
        case UIImageOrientationDownMirrored:
            transform = CGAffineTransformTranslate (transform, image.size.width, 0);
            transform = CGAffineTransformScale (transform, -1, 1);
            istirahat;

        case UIImageOrientationLeftMirrored:
        case UIImageOrientationRightMirrored:
            transform = CGAffineTransformTranslate (transform, image.size.height, 0);
            transform = CGAffineTransformScale (transform, -1, 1);
            istirahat;
        case UIImageOrientationUp:
        case UIImageOrientationDown:
        case UIImageOrientationLeft:
        case UIImageOrientationRight:
            istirahat;
    }

    // Sekarang kita menggambar CGImage yang mendasarinya ke dalam konteks baru, menerapkan transformasi
    // dihitung di atas.
    CGContextRef ctx = CGBitmapContextCreate (NULL, image.size.width, image.size.height,
            CGImageGetBitsPerComponent (image.CGImage), 0,
            CGImageGetColorSpace (image.CGImage),
            CGImageGetBitmapInfo (image.CGImage));
    CGContextConcatCTM (ctx, transform);
    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);
            istirahat;

        default:
            CGContextDrawImage (ctx, CGRectMake (0, 0, image.size.width, image.size.height), image.CGImage);
            istirahat;
    }

    // Dan sekarang kita baru saja membuat UIImage baru dari konteks gambar
    CGImageRef cgimg = CGBitmapContextCreateImage (ctx);
    UIImage * img = [UIImage imageWithCGImage: cgimg];
    CGContextRelease (ctx);
    CGImageRelease (cgimg);
    kembali img;

}
Nowytech
sumber