通过保持纵横比和宽度调整 UIImage 的大小
Posted
技术标签:
【中文标题】通过保持纵横比和宽度调整 UIImage 的大小【英文标题】:Resize UIImage by keeping Aspect ratio and width 【发布时间】:2011-11-30 12:30:23 【问题描述】:我在许多帖子中看到通过保持纵横比来调整图像大小。这些函数在调整大小时使用 RECT 的固定点(宽度和高度)。但是在我的项目中,我需要单独根据宽度调整视图的大小,高度应该根据纵横比自动获取。 任何人都可以帮助我实现这一目标。
【问题讨论】:
【参考方案1】:最简单的方法是设置UIImageView
的框架并将contentMode
设置为调整大小选项之一。
代码是这样的 - 这可以用作实用方法 -
+ (UIImage *)imageWithImage:(UIImage *)image scaledToSize:(CGSize)newSize
UIGraphicsBeginImageContext(newSize);
[image drawInRect:CGRectMake(0, 0, newSize.width, newSize.height)];
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return newImage;
【讨论】:
请记住 OP 没有提到 UIImageView。相反,他可能想直接调整 [a] UIImage 的 [copy of a] UIImage 的纵横比,这在您进行 CoreGraphics 工作时非常方便。【参考方案2】:如果您知道新尺寸的高度和宽度,Srikar 的方法非常有效。 例如,如果您只知道要缩放到的宽度而不关心高度,则首先必须计算高度的比例因子。
+(UIImage*)imageWithImage: (UIImage*) sourceImage scaledToWidth: (float) i_width
float oldWidth = sourceImage.size.width;
float scaleFactor = i_width / oldWidth;
float newHeight = sourceImage.size.height * scaleFactor;
float newWidth = oldWidth * scaleFactor;
UIGraphicsBeginImageContext(CGSizeMake(newWidth, newHeight));
[sourceImage drawInRect:CGRectMake(0, 0, newWidth, newHeight)];
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return newImage;
【讨论】:
这里其实不需要newWidth
变量,它已经是i_width
。
您还需要除以高度,并使用更接近 0 的值比较缩放因子。上面的代码仅适用于宽度大于高度的图像
如果我还想知道我的高度比率并通过缩放宽度或高度来适应,我只需要除以高度。但由于 TO 明确要求保持比例和宽度,而不是宽度或高度,我的回答是完全正确的。
很好的答案,谢谢。还有一件事:如果您使用此方法遇到任何图像质量损失,请使用UIGraphicsBeginImageContextWithOptions(CGSizeMake(newWidth, newHeight), NO, 0);
而不是UIGraphicsBeginImageContext(CGSizeMake(newWidth, newHeight));
【参考方案3】:
如果您不知道图像是纵向还是横向(例如用户用相机拍照),我创建了另一个采用最大宽度和高度参数的方法。
假设您有一个UIImage *myLargeImage
,比例为 4:3。
UIImage *myResizedImage = [ImageUtilities imageWithImage:myLargeImage
scaledToMaxWidth:1024
maxHeight:1024];
如果是横向,则调整后的 UIImage 将为 1024x768; 768x1024(如果是纵向)。此方法还将为视网膜显示生成更高分辨率的图像。
+ (UIImage *)imageWithImage:(UIImage *)image scaledToSize:(CGSize)size
if ([[UIScreen mainScreen] respondsToSelector:@selector(scale)])
UIGraphicsBeginImageContextWithOptions(size, NO, [[UIScreen mainScreen] scale]);
else
UIGraphicsBeginImageContext(size);
[image drawInRect:CGRectMake(0, 0, size.width, size.height)];
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return newImage;
+ (UIImage *)imageWithImage:(UIImage *)image scaledToMaxWidth:(CGFloat)width maxHeight:(CGFloat)height
CGFloat oldWidth = image.size.width;
CGFloat oldHeight = image.size.height;
CGFloat scaleFactor = (oldWidth > oldHeight) ? width / oldWidth : height / oldHeight;
CGFloat newHeight = oldHeight * scaleFactor;
CGFloat newWidth = oldWidth * scaleFactor;
CGSize newSize = CGSizeMake(newWidth, newHeight);
return [ImageUtilities imageWithImage:image scaledToSize:newSize];
【讨论】:
这是最好的,但它总是返回我定义大小的两倍 如果你只想缩小而不是放大,不要忘记启动 imageWithImage:scaledToMaxWidth:maxHeight: 方法: if (image.size.width 要适应最大宽度和最大高度,您需要最小比率作为比例因子:min(ratioX, ratioY)
。否则,如果宽度较大,它可能不适合最大高度。
ImageUtilities 在哪里?【参考方案4】:
只需导入 AVFoundation 并使用AVMakeRectWithAspectRatioInsideRect(CGRectCurrentSize, CGRectMake(0, 0, YOUR_WIDTH, CGFLOAT_MAX)
【讨论】:
【参考方案5】:改进 Ryan 的回答:
+ (UIImage *)imageWithImage:(UIImage *)image scaledToSize:(CGSize)size
CGFloat oldWidth = image.size.width;
CGFloat oldHeight = image.size.height;
//You may need to take some retina adjustments into consideration here
CGFloat scaleFactor = (oldWidth > oldHeight) ? width / oldWidth : height / oldHeight;
return [UIImage imageWithCGImage:image.CGImage scale:scaleFactor orientation:UIImageOrientationUp];
【讨论】:
【参考方案6】:感谢@Maverick1st 算法,我将它实现为Swift
,在我的例子中高度是输入参数
class func resizeImage(image: UIImage, newHeight: CGFloat) -> UIImage
let scale = newHeight / image.size.height
let newWidth = image.size.width * scale
UIGraphicsBeginImageContext(CGSizeMake(newWidth, newHeight))
image.drawInRect(CGRectMake(0, 0, newWidth, newHeight))
let newImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return newImage
【讨论】:
【参考方案7】:此方法是 UIImage 上的一个类别。使用 AVFoundation 进行缩放以适应几行代码。
不要忘记导入#import <AVFoundation/AVFoundation.h>
。
@implementation UIImage (Helper)
- (UIImage *)imageScaledToFitToSize:(CGSize)size
CGRect scaledRect = AVMakeRectWithAspectRatioInsideRect(self.size, CGRectMake(0, 0, size.width, size.height));
UIGraphicsBeginImageContextWithOptions(size, NO, 0);
[self drawInRect:scaledRect];
UIImage *scaledImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return scaledImage;
@end
【讨论】:
发现这可以为我提供最好的结果,同时占用最少的内存。 +1【参考方案8】:Ryan 的解决方案@Ryan 在快速代码中
使用:
func imageWithSize(image: UIImage,size: CGSize)->UIImage
if UIScreen.mainScreen().respondsToSelector("scale")
UIGraphicsBeginImageContextWithOptions(size,false,UIScreen.mainScreen().scale);
else
UIGraphicsBeginImageContext(size);
image.drawInRect(CGRectMake(0, 0, size.width, size.height));
var newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return newImage;
//Summon this function VVV
func resizeImageWithAspect(image: UIImage,scaledToMaxWidth width:CGFloat,maxHeight height :CGFloat)->UIImage
let oldWidth = image.size.width;
let oldHeight = image.size.height;
let scaleFactor = (oldWidth > oldHeight) ? width / oldWidth : height / oldHeight;
let newHeight = oldHeight * scaleFactor;
let newWidth = oldWidth * scaleFactor;
let newSize = CGSizeMake(newWidth, newHeight);
return imageWithSize(image, size: newSize);
【讨论】:
【参考方案9】:嗯,我们在这里调整图像大小的好答案很少,但我只是根据我的需要进行修改。希望这对像我这样的人有所帮助。
我的要求是
-
如果图像宽度大于 1920,则将其调整为 1920 宽度,并保持原始纵横比的高度。
如果图像高度超过 1080,则将其调整为 1080 高度,并保持原始纵横比的宽度。
if (originalImage.size.width > 1920)
CGSize newSize;
newSize.width = 1920;
newSize.height = (1920 * originalImage.size.height) / originalImage.size.width;
originalImage = [ProfileEditExperienceViewController imageWithImage:originalImage scaledToSize:newSize];
if (originalImage.size.height > 1080)
CGSize newSize;
newSize.width = (1080 * originalImage.size.width) / originalImage.size.height;
newSize.height = 1080;
originalImage = [ProfileEditExperienceViewController imageWithImage:originalImage scaledToSize:newSize];
+ (UIImage *)imageWithImage:(UIImage *)image scaledToSize:(CGSize)newSize
UIGraphicsBeginImageContext(newSize);
[image drawInRect:CGRectMake(0, 0, newSize.width, newSize.height)];
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return newImage;
感谢@Srikar Appal ,我使用了他的方法来调整大小。
您也可以查看this 以进行调整大小计算。
【讨论】:
【参考方案10】:我用更简单的方法解决了它
UIImage *placeholder = [UIImage imageNamed:@"OriginalImage.png"];
self.yourImageview.image = [UIImage imageWithCGImage:[placeholder CGImage] scale:(placeholder.scale * 1.5)
orientation:(placeholder.imageOrientation)];
缩放倍数将定义图像的缩放,倍数越大图像越小。这样您就可以检查适合您的屏幕的内容。
或者您也可以通过除以图像宽度/屏幕宽度来获得乘数。
【讨论】:
【参考方案11】:最佳答案 Maverick 1st 已正确翻译为 Swift(使用最新的 swift 3):
func imageWithImage (sourceImage:UIImage, scaledToWidth: CGFloat) -> UIImage
let oldWidth = sourceImage.size.width
let scaleFactor = scaledToWidth / oldWidth
let newHeight = sourceImage.size.height * scaleFactor
let newWidth = oldWidth * scaleFactor
UIGraphicsBeginImageContext(CGSize(width:newWidth, height:newHeight))
sourceImage.draw(in: CGRect(x:0, y:0, width:newWidth, height:newHeight))
let newImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return newImage!
【讨论】:
【参考方案12】:以编程方式:
imageView.contentMode = UIViewContentModeScaleAspectFit;
故事板:
【讨论】:
它有效,但减少了内存占用,您可以使应用程序运行得更快,例如加载大量缩略图。 那是 UIImageView,不是 UIImage。有时,您需要在没有 UIImageView 的情况下进行绘图。【参考方案13】:在 Swift 3 中有一些变化。 这是 UIImage 的扩展:
public extension UIImage
public func resize(height: CGFloat) -> UIImage?
let scale = height / self.size.height
let width = self.size.width * scale
UIGraphicsBeginImageContext(CGSize(width: width, height: height))
self.draw(in: CGRect(x:0, y:0, width:width, height:height))
let resultImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return resultImage
【讨论】:
【参考方案14】:这个对我来说是完美的。保持纵横比并采用maxLength
。宽度或高度不会超过maxLength
-(UIImage*)imageWithImage: (UIImage*) sourceImage maxLength: (float) maxLength
CGFloat scaleFactor = maxLength / MAX(sourceImage.size.width, sourceImage.size.height);
float newHeight = sourceImage.size.height * scaleFactor;
float newWidth = sourceImage.size.width * scaleFactor;
UIGraphicsBeginImageContext(CGSizeMake(newWidth, newHeight));
[sourceImage drawInRect:CGRectMake(0, 0, newWidth, newHeight)];
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return newImage;
【讨论】:
【参考方案15】:根据可用宽度计算图像的最佳高度。
import Foundation
public extension UIImage
public func height(forWidth width: CGFloat) -> CGFloat
let boundingRect = CGRect(
x: 0,
y: 0,
width: width,
height: CGFloat(MAXFLOAT)
)
let rect = AVMakeRect(
aspectRatio: size,
insideRect: boundingRect
)
return rect.size.height
【讨论】:
如果有人要回答这个问题,则需要“import AVFoundation”才能使其适用于 Swift 5,【参考方案16】:extension UIImage
/// Returns a image that fills in newSize
func resizedImage(newSize: CGSize) -> UIImage?
guard size != newSize else return self
let hasAlpha = false
let scale: CGFloat = 0.0
UIGraphicsBeginImageContextWithOptions(newSize, !hasAlpha, scale)
draw(in: CGRect(x: 0, y: 0, width: newSize.width, height: newSize.height))
let newImage: UIImage? = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return newImage
/// Returns a resized image that fits in rectSize, keeping it's aspect ratio
/// Note that the new image size is not rectSize, but within it.
func resizedImageWithinRect(rectSize: CGSize) -> UIImage?
let widthFactor = size.width / rectSize.width
let heightFactor = size.height / rectSize.height
var resizeFactor = widthFactor
if size.height > size.width
resizeFactor = heightFactor
let newSize = CGSize(width: size.width / resizeFactor, height: size.height / resizeFactor)
let resized = resizedImage(newSize: newSize)
return resized
当比例设置为 0.0 时,将使用主屏幕的比例因子,对于 Retina 显示器,比例因子为 2.0 或更高(iPhone 6 Plus 为 3.0)。
【讨论】:
【参考方案17】:Swift 5 版本的 aspect-fit-to-height,基于 @János 的回答
使用现代的UIGraphicsImageRenderer
API,因此保证返回有效的UIImage
。
extension UIImage
/// Given a required height, returns a (rasterised) copy
/// of the image, aspect-fitted to that height.
func aspectFittedToHeight(_ newHeight: CGFloat) -> UIImage
let scale = newHeight / self.size.height
let newWidth = self.size.width * scale
let newSize = CGSize(width: newWidth, height: newHeight)
let renderer = UIGraphicsImageRenderer(size: newSize)
return renderer.image _ in
self.draw(in: CGRect(origin: .zero, size: newSize))
您可以将它与(基于矢量的)PDF 图像资源结合使用,以在任何渲染尺寸下保持质量。
【讨论】:
【参考方案18】:Swift 5 中的 Zeeshan Tufail 和 Womble 答案略有改进。
在这里,我们有 2 个函数的扩展,可以将图像缩放到任意维度的 maxLength
和 jpeg 压缩。
extension UIImage
func aspectFittedToMaxLengthData(maxLength: CGFloat, compressionQuality: CGFloat) -> Data
let scale = maxLength / max(self.size.height, self.size.width)
let format = UIGraphicsImageRendererFormat()
format.scale = scale
let renderer = UIGraphicsImageRenderer(size: self.size, format: format)
return renderer.jpegData(withCompressionQuality: compressionQuality) context in
self.draw(in: CGRect(origin: .zero, size: self.size))
func aspectFittedToMaxLengthImage(maxLength: CGFloat, compressionQuality: CGFloat) -> UIImage?
let newImageData = aspectFittedToMaxLengthData(maxLength: maxLength, compressionQuality: compressionQuality)
return UIImage(data: newImageData)
【讨论】:
【参考方案19】:如果有人在 Swift 5 中需要这个解决方案:
private func resizeImage(image: UIImage, newHeight: CGFloat) -> UIImage
let scale = newHeight / image.size.height
let newWidth = image.size.width * scale
UIGraphicsBeginImageContext(CGSize(width:newWidth, height:newHeight))
image.draw(in:CGRect(x:0, y:0, width:newWidth, height:newHeight))
let newImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return newImage
【讨论】:
以上是关于通过保持纵横比和宽度调整 UIImage 的大小的主要内容,如果未能解决你的问题,请参考以下文章