Как обрезать UIImage?
Я разрабатываю приложение, в котором я обрабатываю изображение, используя его пиксели, но при обработке этого изображения требуется много времени. Поэтому я хочу обрезать UIImage (Только средняя часть изображения, то есть удаление/выталкивание граничной части изображения). У меня есть код разработки,
- (NSInteger) processImage1: (UIImage*) image
{
CGFloat width = image.size.width;
CGFloat height = image.size.height;
struct pixel* pixels = (struct pixel*) calloc(1, image.size.width * image.size.height * sizeof(struct pixel));
if (pixels != nil)
{
// Create a new bitmap
CGContextRef context = CGBitmapContextCreate(
(void*) pixels,
image.size.width,
image.size.height,
8,
image.size.width * 4,
CGImageGetColorSpace(image.CGImage),
kCGImageAlphaPremultipliedLast
);
if (context != NULL)
{
// Draw the image in the bitmap
CGContextDrawImage(context, CGRectMake(0.0f, 0.0f, image.size.width, image.size.height), image.CGImage);
NSUInteger numberOfPixels = image.size.width * image.size.height;
NSMutableArray *numberOfPixelsArray = [[[NSMutableArray alloc] initWithCapacity:numberOfPixelsArray] autorelease];
}
Как я беру (выгуливая за пределами границы) среднюю часть UIImage?????????
Ответы
Ответ 1
Попробуйте что-то вроде этого:
CGImageRef imageRef = CGImageCreateWithImageInRect([largeImage CGImage], cropRect);
image = [UIImage imageWithCGImage:imageRef];
CGImageRelease(imageRef);
Примечание: cropRect - это меньший прямоугольник со средней частью изображения...
Ответ 2
Я искал способ получить произвольную прямоугольную обрезку (т.е. суб-изображение) UIImage.
Большинство решений, которые я пробовал, не работают, если ориентация изображения - это ничего, кроме UIImageOrientationUp.
Например:
http://www.hive05.com/2008/11/crop-an-image-using-the-iphone-sdk/
Обычно, если вы используете свою iPhone-камеру, у вас будут другие ориентации, такие как UIImageOrientationLeft, и вы не получите правильную культуру с помощью вышеперечисленного. Это связано с использованием CGImageRef/CGContextDrawImage, которые отличаются в системе координат относительно UIImage.
В приведенном ниже коде используются методы UI * (без CGImageRef), и я тестировал это с образами вверх/вниз/влево/вправо, и, похоже, он отлично работает.
// get sub image
- (UIImage*) getSubImageFrom: (UIImage*) img WithRect: (CGRect) rect {
UIGraphicsBeginImageContext(rect.size);
CGContextRef context = UIGraphicsGetCurrentContext();
// translated rectangle for drawing sub image
CGRect drawRect = CGRectMake(-rect.origin.x, -rect.origin.y, img.size.width, img.size.height);
// clip to the bounds of the image context
// not strictly necessary as it will get clipped anyway?
CGContextClipToRect(context, CGRectMake(0, 0, rect.size.width, rect.size.height));
// draw image
[img drawInRect:drawRect];
// grab image
UIImage* subImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return subImage;
}
Ответ 3
В конечном счете это будет быстрее, при этом гораздо меньше будет создано изображение из атласов спрайтов, если вы можете установить не только изображение для UIImageView, но и верхнее левое смещение для отображения в этом UIImage. Возможно, это возможно. Это, безусловно, устранит много усилий!
Между тем, я создал эти полезные функции в классе утилиты, который я использую в своих приложениях. Он создает UIImage из части другого UIImage, с возможностью поворота, масштабирования и переворачивания с использованием стандартных значений UIImageOrientation для указания. Масштабирование пикселей сохраняется с исходного изображения.
Мое приложение создает много UIImages во время инициализации, и это обязательно требует времени. Но некоторые изображения не нужны, пока не будет выбрана определенная вкладка. Чтобы обеспечить более быструю загрузку, я мог бы создать их в отдельном потоке, порожденном при запуске, а затем просто подождать, пока это не будет сделано, если эта вкладка будет выбрана.
Этот код также размещен на Самый эффективный способ рисования части изображения в iOS
+ (UIImage*)imageByCropping:(UIImage *)imageToCrop toRect:(CGRect)aperture {
return [ChordCalcController imageByCropping:imageToCrop toRect:aperture withOrientation:UIImageOrientationUp];
}
// Draw a full image into a crop-sized area and offset to produce a cropped, rotated image
+ (UIImage*)imageByCropping:(UIImage *)imageToCrop toRect:(CGRect)aperture withOrientation:(UIImageOrientation)orientation {
// convert y coordinate to origin bottom-left
CGFloat orgY = aperture.origin.y + aperture.size.height - imageToCrop.size.height,
orgX = -aperture.origin.x,
scaleX = 1.0,
scaleY = 1.0,
rot = 0.0;
CGSize size;
switch (orientation) {
case UIImageOrientationRight:
case UIImageOrientationRightMirrored:
case UIImageOrientationLeft:
case UIImageOrientationLeftMirrored:
size = CGSizeMake(aperture.size.height, aperture.size.width);
break;
case UIImageOrientationDown:
case UIImageOrientationDownMirrored:
case UIImageOrientationUp:
case UIImageOrientationUpMirrored:
size = aperture.size;
break;
default:
assert(NO);
return nil;
}
switch (orientation) {
case UIImageOrientationRight:
rot = 1.0 * M_PI / 2.0;
orgY -= aperture.size.height;
break;
case UIImageOrientationRightMirrored:
rot = 1.0 * M_PI / 2.0;
scaleY = -1.0;
break;
case UIImageOrientationDown:
scaleX = scaleY = -1.0;
orgX -= aperture.size.width;
orgY -= aperture.size.height;
break;
case UIImageOrientationDownMirrored:
orgY -= aperture.size.height;
scaleY = -1.0;
break;
case UIImageOrientationLeft:
rot = 3.0 * M_PI / 2.0;
orgX -= aperture.size.height;
break;
case UIImageOrientationLeftMirrored:
rot = 3.0 * M_PI / 2.0;
orgY -= aperture.size.height;
orgX -= aperture.size.width;
scaleY = -1.0;
break;
case UIImageOrientationUp:
break;
case UIImageOrientationUpMirrored:
orgX -= aperture.size.width;
scaleX = -1.0;
break;
}
// set the draw rect to pan the image to the right spot
CGRect drawRect = CGRectMake(orgX, orgY, imageToCrop.size.width, imageToCrop.size.height);
// create a context for the new image
UIGraphicsBeginImageContextWithOptions(size, NO, imageToCrop.scale);
CGContextRef gc = UIGraphicsGetCurrentContext();
// apply rotation and scaling
CGContextRotateCTM(gc, rot);
CGContextScaleCTM(gc, scaleX, scaleY);
// draw the image to our clipped context using the offset rect
CGContextDrawImage(gc, drawRect, imageToCrop.CGImage);
// pull the image from our cropped context
UIImage *cropped = UIGraphicsGetImageFromCurrentImageContext();
// pop the context to get back to the default
UIGraphicsEndImageContext();
// Note: this is autoreleased
return cropped;
}
Ответ 4
Поскольку мне это было нужно сейчас, вот код M-V в Swift 4:
func imageWithImage(image: UIImage, croppedTo rect: CGRect) -> UIImage {
UIGraphicsBeginImageContext(rect.size)
let context = UIGraphicsGetCurrentContext()
let drawRect = CGRect(x: -rect.origin.x, y: -rect.origin.y,
width: image.size.width, height: image.size.height)
context?.clip(to: CGRect(x: 0, y: 0,
width: rect.size.width, height: rect.size.height))
image.draw(in: drawRect)
let subImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return subImage!
}
Ответ 5
Если вы хотите, чтобы портрет обрезал центр каждой фотографии.
Используйте решение @M-V и замените cropRect.
CGFloat height = imageTaken.size.height;
CGFloat width = imageTaken.size.width;
CGFloat newWidth = height * 9 / 16;
CGFloat newX = abs((width - newWidth)) / 2;
CGRect cropRect = CGRectMake(newX,0, newWidth ,height);
Ответ 6
Я хотел иметь возможность обрезать из области на основе соотношения сторон и масштабировать до размера, основанного на внешней граничной протяженности. Вот моя вариация:
import AVFoundation
import ImageIO
class Image {
class func crop(image:UIImage, source:CGRect, aspect:CGSize, outputExtent:CGSize) -> UIImage {
let sourceRect = AVMakeRectWithAspectRatioInsideRect(aspect, source)
let targetRect = AVMakeRectWithAspectRatioInsideRect(aspect, CGRect(origin: CGPointZero, size: outputExtent))
let opaque = true, deviceScale:CGFloat = 0.0 // use scale of device main screen
UIGraphicsBeginImageContextWithOptions(targetRect.size, opaque, deviceScale)
let scale = max(
targetRect.size.width / sourceRect.size.width,
targetRect.size.height / sourceRect.size.height)
let drawRect = CGRect(origin: -sourceRect.origin * scale, size: image.size * scale)
image.drawInRect(drawRect)
let scaledImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return scaledImage
}
}
Есть несколько вещей, которые я нашел сбивчивыми, отдельные проблемы обрезки и изменения размера. Кадрирование обрабатывается с источником прямоугольника, который вы передаете drawInRect, а масштабирование обрабатывается частью размера. В моем случае мне нужно было связать размер прямоугольника обрезки на источнике, с моим выходным прямоугольником с одинаковым соотношением сторон. Масштабный коэффициент затем выводится/вводится, и это необходимо применять к drawRect (передается drawInRect).
Одно из предостережений заключается в том, что этот подход эффективно предполагает, что изображение, которое вы рисуете, больше, чем контекст изображения. Я не тестировал это, но я думаю, что вы можете использовать этот код для обработки обрезки/масштабирования, но явно определяя параметр масштаба как вышеупомянутый параметр масштаба. По умолчанию UIKit применяет множитель на основе разрешения экрана.
Наконец, следует отметить, что этот подход UIKit выше, чем подходы CoreGraphics/Quartz и Core Image, и, похоже, справляется с проблемами ориентации изображений. Также стоит отметить, что это довольно быстро, во-вторых, ImageIO, в соответствии с этим сообщением здесь: http://nshipster.com/image-resizing/
Ответ 7
Используя функцию
CGContextClipToRect(context, CGRectMake(0, 0, size.width, size.height));
Вот пример кода, используемый для другой цели, но клипы в порядке.
- (UIImage *)aspectFillToSize:(CGSize)size
{
CGFloat imgAspect = self.size.width / self.size.height;
CGFloat sizeAspect = size.width/size.height;
CGSize scaledSize;
if (sizeAspect > imgAspect) { // increase width, crop height
scaledSize = CGSizeMake(size.width, size.width / imgAspect);
} else { // increase height, crop width
scaledSize = CGSizeMake(size.height * imgAspect, size.height);
}
UIGraphicsBeginImageContextWithOptions(size, NO, 0.0f);
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextClipToRect(context, CGRectMake(0, 0, size.width, size.height));
[self drawInRect:CGRectMake(0.0f, 0.0f, scaledSize.width, scaledSize.height)];
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return image;
}
Ответ 8
Свифт 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
}
}