Thay đổi kích thước UIImage bằng cách giữ tỷ lệ và chiều rộng của Aspect


136

Tôi thấy trong nhiều bài viết để thay đổi kích thước hình ảnh bằng cách giữ tỷ lệ khung hình. Các chức năng này sử dụng các điểm cố định (Chiều rộng và Chiều cao) cho RECT trong khi thay đổi kích thước. Nhưng trong dự án của tôi, tôi cần thay đổi kích thước khung nhìn chỉ dựa trên Độ rộng, Chiều cao phải được lấy tự động dựa trên tỷ lệ khung hình. bất cứ ai giúp tôi đạt được điều này.

Câu trả lời:


228

Phương pháp của Srikar hoạt động rất tốt, nếu bạn biết cả chiều cao chiều rộng của Kích thước mới của mình. Ví dụ, nếu bạn chỉ biết chiều rộng bạn muốn chia tỷ lệ và không quan tâm đến chiều cao trước tiên bạn phải tính hệ số tỷ lệ của chiều cao.

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

22
Bạn không thực sự cần newWidthbiến ở đây, mặc dù vậy, nó đã có i_width.
Matthew Quiros

2
Bạn cũng cần chia theo chiều cao và so sánh các yếu tố tỷ lệ bằng cách sử dụng giá trị nào gần bằng 0. mã ở trên sẽ chỉ hoạt động với hình ảnh rộng hơn chiều cao
IceForge

1
Tôi chỉ cần chia theo chiều cao nếu tôi cũng muốn biết tỷ lệ chiều cao của mình và phù hợp bằng cách chia tỷ lệ chiều rộng hoặc chiều cao. nhưng vì TO hỏi rõ ràng về việc giữ tỷ lệ và chiều rộng, chứ không phải chiều rộng hay chiều cao, nên câu trả lời của tôi là hoàn toàn chính xác.
Maverick1st

12
Câu trả lời tuyệt vời, cảm ơn. Một điều nữa: nếu bạn gặp phải bất kỳ sự giảm chất lượng hình ảnh nào khi sử dụng phương pháp này thì hãy sử dụng UIGraphicsBeginImageContextWithOptions(CGSizeMake(newWidth, newHeight), NO, 0);thay vào đóUIGraphicsBeginImageContext(CGSizeMake(newWidth, newHeight));
skornos

57

Nếu bạn không biết hình ảnh sẽ là dọc hay ngang (ví dụ: người dùng chụp ảnh bằng máy ảnh), tôi đã tạo một phương pháp khác lấy tham số chiều rộng và chiều cao tối đa.

Hãy nói rằng bạn có UIImage *myLargeImagetỷ lệ 4: 3.

UIImage *myResizedImage = [ImageUtilities imageWithImage:myLargeImage 
                                        scaledToMaxWidth:1024 
                                               maxHeight:1024];

UIImage đã thay đổi kích thước sẽ là 1024x768 nếu nằm ngang; 768x1024 nếu chân dung. Phương pháp này cũng sẽ tạo ra hình ảnh độ phân giải cao hơn để hiển thị võng mạc.

+ (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];
}

1
Đây là điều tốt nhất nhưng nó luôn trả lại gấp đôi kích thước đã xác định của tôi
Mashhadi

2
Nếu bạn chỉ muốn thu nhỏ kích thước, không tăng kích thước, đừng quên khởi động imageWithImage: scaledToMaxWidth: maxHeight: phương thức với: if (image.size. Thong <width && image.size.height <height) {return image; }
Arjan

5
Để vừa với chiều rộng tối đa và chiều cao tối đa, bạn cần tỷ lệ tối thiểu làm hệ số tỷ lệ: min(ratioX, ratioY) . Mặt khác, nếu chiều rộng lớn hơn, nó có thể không vừa với chiều cao tối đa.
Jason Sturges

ImageUtilities nó ở đâu?
tong

42

Câu trả lời hay nhất của Maverick 1st được dịch chính xác sang Swift (làm việc với swift 3 mới nhất ):

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

38

cảm ơn @ Maverick1st thuật toán, tôi đã triển khai nó Swift, trong trường hợp chiều cao của tôi là tham số đầu vào

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
}

18

Phương pháp này là một thể loại trên UIImage. Liệu quy mô có phù hợp với một vài dòng mã bằng AVFoundation. Đừng quên nhập khẩu #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

2
Tìm thấy điều này để cung cấp kết quả tốt nhất cho tôi với dấu chân bộ nhớ nhỏ nhất. +1
Tommie C.

11

Phiên bản Swift 5 về chiều cao phù hợp với chiều cao , dựa trên câu trả lời của @ János

Sử dụng UIGraphicsImageRendererAPI hiện đại , do đó, một giá trị hợp lệ UIImageđược đảm bảo trả lại.

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

Bạn có thể sử dụng kết hợp với tài sản hình ảnh PDF (dựa trên vector) để duy trì chất lượng ở bất kỳ kích thước kết xuất nào.


7

Cách đơn giản nhất là đặt khung của bạn UIImageViewvà đặtcontentMode một trong các tùy chọn thay đổi kích thước.

Mã đi như thế này - Điều này có thể được sử dụng như một phương thức tiện ích -

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

Hãy nhớ rằng OP đã không đề cập đến một UIImageView. Thay vào đó, anh ta có lẽ muốn phù hợp với khía cạnh [bản sao của] UIImage trực tiếp, đây là một điều rất tiện lợi khi bạn làm CoreGraphics.
Womble

6

Lập trình:

imageView.contentMode = UIViewContentModeScaleAspectFit;

Bảng phân cảnh:

nhập mô tả hình ảnh ở đây


nó hoạt động, NHƯNG giảm dấu chân bộ nhớ, bạn có thể làm cho ứng dụng hoạt động nhanh hơn, ví dụ như tải rất nhiều hình thu nhỏ.
ingconti

Đó là UIImageView, không phải UIImage. Đôi khi, bạn cần thực hiện vẽ mà không có UIImageView.
Womble

5

Vâng, chúng tôi có một vài câu trả lời tốt ở đây để thay đổi kích thước hình ảnh, nhưng tôi chỉ sửa đổi theo nhu cầu của mình. Hy vọng điều này sẽ giúp một người như tôi.

Yêu cầu của tôi là

  1. Nếu chiều rộng hình ảnh lớn hơn 1920, hãy thay đổi kích thước với chiều rộng 1920 và duy trì chiều cao với tỷ lệ khung hình gốc.
  2. Nếu chiều cao hình ảnh lớn hơn 1080, hãy thay đổi kích thước của nó với chiều cao 1080 và duy trì chiều rộng với tỷ lệ khung hình gốc.

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

Cảm ơn @ Srikar Appal , vì đã thay đổi kích thước, tôi đã sử dụng phương pháp của mình.

Bạn có thể muốn kiểm tra điều này cũng để tính toán thay đổi kích thước.


4

Chỉ cần nhập AVFoundation và sử dụng AVMakeRectWithAspectRatioInsideRect(CGRectCurrentSize, CGRectMake(0, 0, YOUR_WIDTH, CGFLOAT_MAX)


2

Để cải thiện câu trả lời của 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];
    }

2
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)
        UIGraphicsBeginImageContextWithOptions(newSize, false, 0.0)

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

Khi tỷ lệ được đặt thành 0,0, hệ số tỷ lệ của màn hình chính được sử dụng, đối với màn hình Retina là 2.0 hoặc cao hơn (3.0 trên iPhone 6 Plus).


1

Giải pháp của Ryan @Ryan bằng mã nhanh

sử dụng:

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

1

Trong Swift 3 có một số thay đổi. Đây là một phần mở rộng cho 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
    }
}

1

Zeeshan Tufail và Womble trả lời trong Swift 5 với những cải tiến nhỏ. Ở đây chúng tôi có phần mở rộng với 2 chức năng để chia tỷ lệ hình ảnh thành maxLengthbất kỳ kích thước và nén jpeg nào.

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

0

Điều này là hoàn hảo cho tôi. Giữ tỷ lệ khung hình và mất một maxLength. Chiều rộng hoặc chiều cao sẽ không nhiều hơnmaxLength

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

0

Tính chiều cao tốt nhất của hình ảnh cho chiều rộng có sẵn.

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

-1

Tôi đã giải quyết nó một cách đơn giản hơn nhiều

UIImage *placeholder = [UIImage imageNamed:@"OriginalImage.png"];
self.yourImageview.image = [UIImage imageWithCGImage:[placeholder CGImage] scale:(placeholder.scale * 1.5)
                                  orientation:(placeholder.imageOrientation)];

hệ số nhân của tỷ lệ sẽ xác định sự sai lệch của hình ảnh, càng nhiều số nhân hình ảnh càng nhỏ. Vì vậy, bạn có thể kiểm tra những gì phù hợp với màn hình của bạn.

Hoặc bạn cũng có thể lấy bội số bằng cách chia băng thông hình ảnh / băng thông màn hình.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.