UIImage:调整大小,然后裁剪

我现在几天来一直在抨击这个问题,尽管我总是觉得自己处在启示的边缘,但是我根本无法实现自己的目标。

我在设计的概念阶段就提前想到,从iPhone的相机或库中获取图像,使用相当于“ 方面填充”选项的函数将其缩小到指定的高度,这将是一件微不足道的事情。 UIImageView(完全在代码中),然后裁剪任何不适合通过CGRect的东西。

从相机或图书馆获取原始图像,是微不足道的。 其他两个步骤证明是如此困难,我感到震惊。

附图显示了我正在努力实现的目标。 请人友善地握住我的手? 我迄今为止发现的每个代码示例都似乎粉碎了图像,颠倒过来,看起来像垃圾,画出界限,否则就不能正常工作。

我需要同样的东西 – 在我的情况下,选择缩放后的尺寸,然后裁剪每一端以适应宽度。 (我在景观工作,所以可能没有注意到肖像模式中的任何缺陷。)这是我的代码 – 这是UIImage上的一个关于categeory的一部分。 我的代码中的目标大小始终设置为设备的全屏大小。

@implementation UIImage (Extras) #pragma mark - #pragma mark Scale and crop image - (UIImage*)imageByScalingAndCroppingForSize:(CGSize)targetSize { UIImage *sourceImage = self; UIImage *newImage = nil; CGSize imageSize = sourceImage.size; CGFloat width = imageSize.width; CGFloat height = imageSize.height; CGFloat targetWidth = targetSize.width; CGFloat targetHeight = targetSize.height; CGFloat scaleFactor = 0.0; CGFloat scaledWidth = targetWidth; CGFloat scaledHeight = targetHeight; CGPoint thumbnailPoint = CGPointMake(0.0,0.0); if (CGSizeEqualToSize(imageSize, targetSize) == NO) { CGFloat widthFactor = targetWidth / width; CGFloat heightFactor = targetHeight / height; if (widthFactor > heightFactor) { scaleFactor = widthFactor; // scale to fit height } else { scaleFactor = heightFactor; // scale to fit width } scaledWidth = width * scaleFactor; scaledHeight = height * scaleFactor; // center the image if (widthFactor > heightFactor) { thumbnailPoint.y = (targetHeight - scaledHeight) * 0.5; } else { if (widthFactor < heightFactor) { thumbnailPoint.x = (targetWidth - scaledWidth) * 0.5; } } } UIGraphicsBeginImageContext(targetSize); // this will crop CGRect thumbnailRect = CGRectZero; thumbnailRect.origin = thumbnailPoint; thumbnailRect.size.width = scaledWidth; thumbnailRect.size.height = scaledHeight; [sourceImage drawInRect:thumbnailRect]; newImage = UIGraphicsGetImageFromCurrentImageContext(); if(newImage == nil) { NSLog(@"could not scale image"); } //pop the context to get back to the default UIGraphicsEndImageContext(); return newImage; } 

较旧的帖子包含调整UIImage大小的方法的代码。 相关部分如下:

 + (UIImage*)imageWithImage:(UIImage*)image scaledToSize:(CGSize)newSize; { UIGraphicsBeginImageContext( newSize ); [image drawInRect:CGRectMake(0,0,newSize.width,newSize.height)]; UIImage* newImage = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); return newImage; } 

就裁剪而言,我相信如果您改变方法使用不同尺寸的缩放而不是上下文,则您的结果图像应该被剪切到上下文的边界。

 + (UIImage *)scaleImage:(UIImage *)image toSize:(CGSize)targetSize { //If scaleFactor is not touched, no scaling will occur CGFloat scaleFactor = 1.0; //Deciding which factor to use to scale the image (factor = targetSize / imageSize) if (image.size.width > targetSize.width || image.size.height > targetSize.height) if (!((scaleFactor = (targetSize.width / image.size.width)) > (targetSize.height / image.size.height))) //scale to fit width, or scaleFactor = targetSize.height / image.size.height; // scale to fit heigth. UIGraphicsBeginImageContext(targetSize); //Creating the rect where the scaled image is drawn in CGRect rect = CGRectMake((targetSize.width - image.size.width * scaleFactor) / 2, (targetSize.height - image.size.height * scaleFactor) / 2, image.size.width * scaleFactor, image.size.height * scaleFactor); //Draw the image into the rect [image drawInRect:rect]; //Saving the image, ending image context UIImage *scaledImage = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); return scaledImage; } 

我建议这个。 她不是美人吗? ;)

有一个伟大的代码相关的调整大小的图像+其他几个操作。 当我试图找出如何调整图像大小的时候,我想到了这个… http://vocaro.com/trevor/blog/2009/10/12/resize-a-uiimage-the-right-way/

干得好。 这一个是完美的;-)

编辑:见下面的评论 – “不适用于某些图像,失败:CGContextSetInterpolationQuality:无效上下文0x0错误”

 // Resizes the image according to the given content mode, taking into account the image's orientation - (UIImage *)resizedImageWithContentMode:(UIViewContentMode)contentMode imageToScale:(UIImage*)imageToScale bounds:(CGSize)bounds interpolationQuality:(CGInterpolationQuality)quality { //Get the size we want to scale it to CGFloat horizontalRatio = bounds.width / imageToScale.size.width; CGFloat verticalRatio = bounds.height / imageToScale.size.height; CGFloat ratio; switch (contentMode) { case UIViewContentModeScaleAspectFill: ratio = MAX(horizontalRatio, verticalRatio); break; case UIViewContentModeScaleAspectFit: ratio = MIN(horizontalRatio, verticalRatio); break; default: [NSException raise:NSInvalidArgumentException format:@"Unsupported content mode: %d", contentMode]; } //...and here it is CGSize newSize = CGSizeMake(imageToScale.size.width * ratio, imageToScale.size.height * ratio); //start scaling it CGRect newRect = CGRectIntegral(CGRectMake(0, 0, newSize.width, newSize.height)); CGImageRef imageRef = imageToScale.CGImage; CGContextRef bitmap = CGBitmapContextCreate(NULL, newRect.size.width, newRect.size.height, CGImageGetBitsPerComponent(imageRef), 0, CGImageGetColorSpace(imageRef), CGImageGetBitmapInfo(imageRef)); CGContextSetInterpolationQuality(bitmap, quality); // Draw into the context; this scales the image CGContextDrawImage(bitmap, newRect, imageRef); // Get the resized image from the context and a UIImage CGImageRef newImageRef = CGBitmapContextCreateImage(bitmap); UIImage *newImage = [UIImage imageWithCGImage:newImageRef]; // Clean up CGContextRelease(bitmap); CGImageRelease(newImageRef); return newImage; } 

这是Jane Sales在Swift中的一个答案。 干杯!

 public func resizeImage(image: UIImage, size: CGSize) -> UIImage? { var returnImage: UIImage? var scaleFactor: CGFloat = 1.0 var scaledWidth = size.width var scaledHeight = size.height var thumbnailPoint = CGPointMake(0, 0) if !CGSizeEqualToSize(image.size, size) { let widthFactor = size.width / image.size.width let heightFactor = size.height / image.size.height if widthFactor > heightFactor { scaleFactor = widthFactor } else { scaleFactor = heightFactor } scaledWidth = image.size.width * scaleFactor scaledHeight = image.size.height * scaleFactor if widthFactor > heightFactor { thumbnailPoint.y = (size.height - scaledHeight) * 0.5 } else if widthFactor < heightFactor { thumbnailPoint.x = (size.width - scaledWidth) * 0.5 } } UIGraphicsBeginImageContextWithOptions(size, true, 0) var thumbnailRect = CGRectZero thumbnailRect.origin = thumbnailPoint thumbnailRect.size.width = scaledWidth thumbnailRect.size.height = scaledHeight image.drawInRect(thumbnailRect) returnImage = UIGraphicsGetImageFromCurrentImageContext() UIGraphicsEndImageContext() return returnImage } 

我修改了Brad Larson的Code。 它将在方面填充图像。

 -(UIImage*) scaleAndCropToSize:(CGSize)newSize; { float ratio = self.size.width / self.size.height; UIGraphicsBeginImageContext(newSize); if (ratio > 1) { CGFloat newWidth = ratio * newSize.width; CGFloat newHeight = newSize.height; CGFloat leftMargin = (newWidth - newHeight) / 2; [self drawInRect:CGRectMake(-leftMargin, 0, newWidth, newHeight)]; } else { CGFloat newWidth = newSize.width; CGFloat newHeight = newSize.height / ratio; CGFloat topMargin = (newHeight - newWidth) / 2; [self drawInRect:CGRectMake(0, -topMargin, newSize.width, newSize.height/ratio)]; } UIImage* newImage = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); return newImage; } 

Xamarin.iOS版本为如何调整大小,然后裁剪UIImage(方面填充)接受的答案如下

  public static UIImage ScaleAndCropImage(UIImage sourceImage, SizeF targetSize) { var imageSize = sourceImage.Size; UIImage newImage = null; var width = imageSize.Width; var height = imageSize.Height; var targetWidth = targetSize.Width; var targetHeight = targetSize.Height; var scaleFactor = 0.0f; var scaledWidth = targetWidth; var scaledHeight = targetHeight; var thumbnailPoint = PointF.Empty; if (imageSize != targetSize) { var widthFactor = targetWidth / width; var heightFactor = targetHeight / height; if (widthFactor > heightFactor) { scaleFactor = widthFactor;// scale to fit height } else { scaleFactor = heightFactor;// scale to fit width } scaledWidth = width * scaleFactor; scaledHeight = height * scaleFactor; // center the image if (widthFactor > heightFactor) { thumbnailPoint.Y = (targetHeight - scaledHeight) * 0.5f; } else { if (widthFactor < heightFactor) { thumbnailPoint.X = (targetWidth - scaledWidth) * 0.5f; } } } UIGraphics.BeginImageContextWithOptions(targetSize, false, 0.0f); var thumbnailRect = new RectangleF(thumbnailPoint, new SizeF(scaledWidth, scaledHeight)); sourceImage.Draw(thumbnailRect); newImage = UIGraphics.GetImageFromCurrentImageContext(); if (newImage == null) { Console.WriteLine("could not scale image"); } //pop the context to get back to the default UIGraphics.EndImageContext(); return newImage; } 

我把Sam Wirch的指南转换成swift ,对我来说效果不错,虽然在最后的形象中有一些非常轻微的“压扁”,我无法解决。

 func resizedCroppedImage(image: UIImage, newSize:CGSize) -> UIImage { var ratio: CGFloat = 0 var delta: CGFloat = 0 var offset = CGPointZero 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) } let clipRect = CGRectMake(-offset.x, -offset.y, (ratio * image.size.width) + delta, (ratio * image.size.height) + delta) UIGraphicsBeginImageContextWithOptions(newSize, true, 0.0) UIRectClip(clipRect) image.drawInRect(clipRect) let newImage = UIGraphicsGetImageFromCurrentImageContext() UIGraphicsEndImageContext() return newImage } 

如果有人想要客观的C版本,那就在他的网站上。

以下简单的代码为我工作。

 [imageView setContentMode:UIViewContentModeScaleAspectFill]; [imageView setClipsToBounds:YES]; 
 scrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(0.0,0.0,ScreenWidth,ScreenHeigth)]; [scrollView setBackgroundColor:[UIColor blackColor]]; [scrollView setDelegate:self]; [scrollView setShowsHorizontalScrollIndicator:NO]; [scrollView setShowsVerticalScrollIndicator:NO]; [scrollView setMaximumZoomScale:2.0]; image=[image scaleToSize:CGSizeMake(ScreenWidth, ScreenHeigth)]; imageView = [[UIImageView alloc] initWithImage:image]; UIImageView* imageViewBk = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"background.png"]]; [self.view addSubview:imageViewBk]; CGRect rect; rect.origin.x=0; rect.origin.y=0; rect.size.width = image.size.width; rect.size.height = image.size.height; [imageView setFrame:rect]; [scrollView setContentSize:[imageView frame].size]; [scrollView setMinimumZoomScale:[scrollView frame].size.width / [imageView frame].size.width]; [scrollView setZoomScale:[scrollView minimumZoomScale]]; [scrollView addSubview:imageView]; [[self view] addSubview:scrollView]; 

那么你可以通过这个屏幕截图到你的形象

 float zoomScale = 1.0 / [scrollView zoomScale]; CGRect rect; rect.origin.x = [scrollView contentOffset].x * zoomScale; rect.origin.y = [scrollView contentOffset].y * zoomScale; rect.size.width = [scrollView bounds].size.width * zoomScale; rect.size.height = [scrollView bounds].size.height * zoomScale; CGImageRef cr = CGImageCreateWithImageInRect([[imageView image] CGImage], rect); UIImage *cropped = [UIImage imageWithCGImage:cr]; CGImageRelease(cr); 
 - (UIImage*)imageScale:(CGFloat)scaleFactor cropForSize:(CGSize)targetSize { targetSize = !targetSize.width?self.size:targetSize; UIGraphicsBeginImageContext(targetSize); // this will crop CGRect thumbnailRect = CGRectZero; thumbnailRect.size.width = targetSize.width*scaleFactor; thumbnailRect.size.height = targetSize.height*scaleFactor; CGFloat xOffset = (targetSize.width- thumbnailRect.size.width)/2; CGFloat yOffset = (targetSize.height- thumbnailRect.size.height)/2; thumbnailRect.origin = CGPointMake(xOffset,yOffset); [self drawInRect:thumbnailRect]; UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext(); if(newImage == nil) { NSLog(@"could not scale image"); } UIGraphicsEndImageContext(); return newImage; } 

下面的例子工作:左图像 – (原始图像); 比例尺为x2的右图

在这里输入图像描述

如果要缩放图像但保留其框架(比例),请按以下方式调用方法:

 [yourImage imageScale:2.0f cropForSize:CGSizeZero]; 

这个问题似乎已经得到了解决,但在我寻求一个解决方案,我可以更容易地理解(和写在Swift),我到达了这一点(也张贴到: 如何裁剪UIImage? )


我希望能够根据纵横比从一个区域裁剪,并根据外边界范围缩放到一个尺寸。 这是我的变化:

 import AVFoundation import ImageIO class Image { class func crop(image:UIImage, crop 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's 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/

Swift版本:

  static func imageWithImage(image:UIImage, newSize:CGSize) ->UIImage { UIGraphicsBeginImageContextWithOptions(newSize, true, UIScreen.mainScreen().scale); image.drawInRect(CGRectMake(0, 0, newSize.width, newSize.height)) let newImage = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); return newImage } 

这是一个Swift 3版的Sam Wirch的指南,由William T.发表

 extension UIImage { static func resizedCroppedImage(image: UIImage, newSize:CGSize) -> UIImage? { var ratio: CGFloat = 0 var delta: CGFloat = 0 var offset = CGPoint.zero if image.size.width > image.size.height { ratio = newSize.width / image.size.width delta = (ratio * image.size.width) - (ratio * image.size.height) offset = CGPoint(x: delta / 2, y: 0) } else { ratio = newSize.width / image.size.height delta = (ratio * image.size.height) - (ratio * image.size.width) offset = CGPoint(x: 0, y: delta / 2) } let clipRect = CGRect(x: -offset.x, y: -offset.y, width: (ratio * image.size.width) + delta, height: (ratio * image.size.height) + delta) UIGraphicsBeginImageContextWithOptions(newSize, true, 0.0) UIRectClip(clipRect) image.draw(in: clipRect) let newImage = UIGraphicsGetImageFromCurrentImageContext() UIGraphicsEndImageContext() return newImage } }