Обрізання UIImage


209

У мене є код, який змінює розмір зображення, щоб я міг змінити розмір у центрі зображення - я використовую це, щоб взяти UIImageі повернути невелике, квадратне зображення зображення, подібне до того, що видно на зображенні альбому додаток Фото. (Я знаю, що міг би скористатись a UIImageViewі відрегулювати режим обрізання для досягнення однакових результатів, але ці зображення іноді відображаються у UIWebViews).

Я почав помічати деякі збої в цьому коді, і я трохи спотикався. У мене є дві різні теорії, і мені цікаво, чи то на базі.

Теорія 1) Обрізання я досягаю шляхом малювання в контексті зображення на екрані мого цільового розміру. Оскільки я хочу центральну частину зображення, я встановлюю CGRectпереданий аргумент drawInRectна щось, що перевищує межі контексту мого зображення. Я сподівався, що це Кошер, але я натомість намагаюся залучити іншу пам’ять, яку я не повинен чіпати?

Теорія 2) Я все це роблю у фоновому потоці. Я знаю, що є частини UIKit, які обмежені основною темою. Я припускав / сподівався, що звернення до перегляду екрана не було одним із таких. Я помиляюся?

(О, як я пропускаю NSImage's drawInRect:fromRect:operation:fraction:метод.)


Якщо ви намагаєтеся діагностувати збій, вам слід запустити додаток під налагоджувачем і робити помітку про те, що відбувається, коли він виходить з ладу. Ви навіть не визначили, чи є викид, який викидається, або ви отримуєте EXC_BAD_ACCESS через звисаючий покажчик. Як тільки ви це знаєте, то можете приступати до створення теорій.
benzado

Досить справедливо. Я не спростовував це під налагоджувачем, хоча в журналі аварій я маю EXC_BAD_ACCESS. Коли я опублікував це, я працював при припущенні, що я зробив дурну помилку в моєму здійсненні і хтось стрибне на нього (наприклад, забувши відсічний шлях).
Джаблер

Для чого варто і хороших відповідей нижче, незважаючи на це, є хороший огляд методик та їх ефективності на NSHipster: nshipster.com/image-resizing . Пурист в мені хотів використовувати CIImage, але прагматик обрав контекст UIKit / image.
Кріс Коновер

Відповіді:


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прямокутника і обрізання буде неправильним. Ви можете відповідно обертати прямокутник обрізання, але щойно створений UIImageбуде мати imageOrientationвгору, так що обрізаний CGImageбуде обертатися всередині нього.
zoul

25
Хочу зазначити, що на дисплеї сітківки вам потрібно подвоїти ширину та висоту cropRect за допомогою цього методу. Просто щось, на що я наткнувся.
petrocket

21
щоб він працював у будь-якій орієнтації:[UIImage imageWithCGImage:imageRef scale:largeImage.scale orientation:largeImage.imageOrientation];
Нікос Караліс

3
Вам слід додати підтримку Retina !!
Mário Carvalho

1
@NicosKaralis, який лише поверне його в потрібну орієнтацію. Однак область, яку ви вирізаєте із зображення, все одно буде помилятися.
Тім Бодейт

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, ні?
Майкл Міор

2
Ви маєте рацію, Майкл, але я вважаю, що вищезазначене рішення є трохи швидшим на пристроях, що не мають сітківки, оскільки це робить лише одну перевірку замість чотирьох множень плюс завдання. На пристроях із сітківкою це лише одна булева перевірка більше, ніж потрібно, тож це питання особистої переваги або цільової придатності.
CGee

2
Чи правильно це використовувати CGImageRelease(imageRef);з включеною ARC?
CGee

3
@Dschee Так. Дивіться stackoverflow.com/questions/7800174/…
Клаас

3
Насправді 4 множення можуть бути швидшими, ніж оцінка однієї умови :) Множини можна досить оптимізувати на сучасних процесорах, тоді як умови можна прогнозувати лише. Але ви праві, це питання переваги. Я вважаю за краще коротший / простіший код через збільшення читабельності.
бер

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? Масштаб зображення може бути не таким, як масштаб екрана.
Майкл Міор

Привіт, я спробував вашу відповідь, і це дає мені, No visible @interface for 'UIImage' declares the selector 'crop'навіть якщо я помістив файли категорій .h та .m у мій проект та імпортував .h у клас, у якому я використовую категорію. Будь-яка ідея?
Алі

Виправлено це. Я пропустив помістити заголовок методу у файл UIImage + Crop.h.
Алі

Я хочу обрізати зображення круглої форми. Так що ми можемо бачити лише круговий шлях, а інший шлях залишається прозорим.
Альфа

Тоді ви можете використовувати 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 2x @ @ 3x, а назви функцій не збігаються.
Вільям Т.

4
Вам потрібен guardперший рядок у випадку UIImage.CGImageповернення nilта навіщо використовуватись, varколи letпрацює ідеально.
NoodleOfDeath

Це правильно, ЯКЩО читайте документи cropping(to:)дуже уважно. Отримане CGImageтверде посилання на більшу, CGImageз якої вона була обрізана. Тож якщо ви хочете вішати лише на обрізане зображення і не потребуєте оригіналу, погляньте на інші рішення.
jsadler

Це не працює із зображеннями, які мають орієнтаційні теги. Область посіву не обертається належним чином.
Макс

1
@Max це тому, що cgImage не підтримує орієнтацію. Якщо UIImage виникає, rightто cgImage слід повернути ccw на 90 градусів, отже, і пряму обрізку слід повернути
MK Yung

49

Ось моя реалізація урожаю UIImage, яка підкоряється властивості imageOrientation. Всі орієнтації були ретельно випробувані.

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

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

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

7
Попередження implicit declaration of function 'rad' is invalid in c99можна видалити, замінивши: rad (90), rad (-90), rad (-180) -> M_PI_2, -M_PI_2, -_M_PI
Sound Blaster

На жаль, вибачте. До вихідного фрагмента додана функція утиліти rad ().
Сергій Рудченко

contains undefined reference for architecture armv7Я пропускаю бібліотеку? CoreGraphics імпортується.
Боб Сприн

1
@SergiiRudchenko "Всі орієнтації були ретельно перевірені". - Чи включає це дзеркальні орієнтації?
Тім Бодейт

@BobSpryn Ні, ви не пропустите бібліотеку. Хоча я не можу пояснити, що означає помилка, заміна radd (), як запропонував SoundBlaster, також виправляє цю помилку.
Тім Бодейт

39

Голова вгору: всі ці відповіді припускають об'єкт CGImageзображення, що не підтримується.

image.CGImageможе повернути нуль, якщо UIImageаркуш підтримується символом a 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
Це саме те, що мені було потрібно, працює у всіх сценаріях, тому краще, ніж будь-яке інше рішення!
Девід Томпсон

2
image.size у першому рядку має бути rect.size UIGraphicsBeginImageContextWithOptions (rect.size, false, image.scale);
Бретт

2
Дякую Бретт, безумовно, саме там. Я оновив код, щоб включити це виправлення.
colinta

Чому це -rect.origin.x не просто rect.origin.x?
Агресор

2
Тому що ми обрізаємо; Іншими словами, аргумент 'rect' говорить: «Я хочу, щоб верхній лівий кут нового зображення починався, скажімо, [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

Я використовую це для проведення пальців по фільтрах (наприклад, як Snapchat), і у мене виникають незначні проблеми зі масштабуванням. Чи є у вашому коді щось, що ви можете запропонувати переглянути? Що може спричинити причину цієї помилки масштабування? Я розмістив тут своє рішення, яке використовує ваш код: stackoverflow.com/questions/23319497/…
Агресор

дуже корисна функція, дякую. будь-які поради, що слід змінити, щоб вирізати фокус на центральній частині зображення?
приватний

ЦЕ ПОВИНЕН БУТИ ВІДПОВІДЬ.
підкова7

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

Більшість відповідей, які я бачив, стосуються лише позиції (0, 0) для (x, y). Гаразд, це один випадок, але я б хотів, щоб мою операцію з обрізанням було зосереджено. Що мені знадобилося певний час, щоб розібратися - це рядок після коментаря WTF.

Візьмемо випадок зображення, знятого з портретною орієнтацією:

  1. Оригінальна висота зображення вища за ширину (Woo, поки не дивно!)
  2. Зображення, яке у власному світі уявляє метод CGImageCreateWithImageInRect, насправді не є портретом, а пейзажем (тому також, якщо ви не використовуєте аргумент орієнтації в конструкторі imageWithCGImage, він відображатиметься як 180 повернутих).
  3. Отже, вам слід уявити собі, що це пейзаж, положення (0, 0) - верхній правий кут зображення.

Сподіваюся, це має сенс! Якщо це не так, спробуйте різні значення, ви побачите, що логіка перевернута, коли справа стосується вибору правильного x, y, ширини та висоти для cropRect.


8

стрімкий3

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

7

Швидке розширення

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

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

4

Найкраще рішення для обрізання UIImage в Swift , з точки зору точності, масштабування пікселів ...:

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

Ось оновлена ​​версія 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 *.

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 = нуль;
    CGRect targetFrame = CGRectMake ((self.scrollView.contentInset.left + self.scrollView.contentOffset.x) * масштаб,
            (self.scrollView.contentInset.top + self.scrollView.contentOffset.y) * шкала,
            self.cropSize.width * шкала,
            self.cropSize.height * шкала);

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

    якщо (contextImage! = NULL) {
        finalImage = [UIImage imageWithCGImage: contextImage
                                         масштаб: self.sourceImage.scale
                                   орієнтація: UIImageOrientationUp];

        CGImageRelease (contextImage);
    }

    повернути фіналImage;
}


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


    якщо (image.imageOrientation == UIImageOrientationUp) повернути зображення;
    CGAffineTransform перетворення = CGAffineTransformIdentity;

    перемикач (image.imageOrientation) {
        випадок UIImageOrientationDown:
        випадок UIImageOrientationDownMirrored:
            перетворення = CGAffineTransformTranslate (перетворення, зображення.розмір.ширина, зображення.розмір) висота);
            перетворення = CGAffineTransformRotate (перетворення, M_PI);
            перерва;

        випадок UIImageOrientationLeft:
        випадок UIImageOrientationLeftMirrored:
            перетворення = CGAffineTransformTranslate (перетворення, зображення. розмір.ширина, 0);
            перетворення = CGAffineTransformRotate (перетворення, M_PI_2);
            перерва;

        випадок UIImageOrientationRight:
        випадок UIImageOrientationRightMirrored:
            перетворення = CGAffineTransformTranslate (перетворення, 0, image.size.height);
            перетворення = CGAffineTransformRotate (перетворення, -M_PI_2);
            перерва;
        випадок UIImageOrientationUp:
        випадок UIImageOrientationUpMirrored:
            перерва;
    }

    перемикач (image.imageOrientation) {
        випадок UIImageOrientationUpMirrored:
        випадок UIImageOrientationDownMirrored:
            перетворення = CGAffineTransformTranslate (перетворення, зображення. розмір.ширина, 0);
            перетворення = CGAffineTransformScale (перетворення, -1, 1);
            перерва;

        випадок UIImageOrientationLeftMirrored:
        випадок UIImageOrientationRightMirrored:
            перетворення = CGAffineTransformTranslate (перетворення, image.size.height, 0);
            перетворення = CGAffineTransformScale (перетворення, -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, перетворення);
    перемикач (image.imageOrientation) {
        випадок UIImageOrientationLeft:
        випадок UIImageOrientationLeftMirrored:
        випадок UIImageOrientationRight:
        випадок UIImageOrientationRightMirrored:
            // Гр ...
            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);
    return img;

}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.