ปรับขนาด UIImage โดยรักษาอัตราส่วนและความกว้าง


138

ฉันเห็นในหลาย ๆ โพสต์เกี่ยวกับการปรับขนาดรูปภาพโดยรักษาอัตราส่วน ฟังก์ชันเหล่านี้ใช้จุดคงที่ (ความกว้างและความสูง) สำหรับ RECT ขณะปรับขนาด แต่ในโครงการของฉันฉันต้องปรับขนาดมุมมองตามความกว้างเพียงอย่างเดียวควรใช้ความสูงโดยอัตโนมัติตามอัตราส่วนภาพ ใครก็ได้ช่วยฉันทำสิ่งนี้ให้สำเร็จ

คำตอบ:


230

วิธีการของ 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;
}

22
คุณไม่ได้จริงๆต้องnewWidthตัวแปรที่นี่ i_widthแต่มันมีอยู่แล้ว
MLQ

2
คุณต้องหารด้วยความสูงด้วยและเปรียบเทียบปัจจัยการปรับขนาดโดยใช้ค่าใดก็ตามที่ใกล้เคียงกับ 0 โค้ดด้านบนจะใช้ได้เฉพาะกับภาพที่กว้างกว่าความสูงเท่านั้น
IceForge

1
ฉันต้องหารด้วยความสูงถ้าฉันต้องการทราบอัตราส่วนความสูงของฉันด้วยและพอดีโดยการปรับขนาดความกว้างหรือความสูง แต่เนื่องจาก TO ถามอย่างชัดเจนเกี่ยวกับการรักษาอัตราส่วนและความกว้างไม่ใช่ความกว้างหรือความสูงคำตอบของฉันจึงถูกต้องทั้งหมด
Maverick1st

12
คำตอบที่ดีขอบคุณ อีกอย่างหนึ่ง: หากคุณพบการสูญเสียคุณภาพของภาพโดยใช้วิธีนี้ให้ใช้UIGraphicsBeginImageContextWithOptions(CGSizeMake(newWidth, newHeight), NO, 0);มากกว่านั้นUIGraphicsBeginImageContext(CGSizeMake(newWidth, newHeight));
skornos

57

หากคุณไม่ทราบว่าภาพจะเป็นแนวตั้งหรือแนวนอน (เช่นผู้ใช้ถ่ายภาพด้วยกล้อง) ฉันได้สร้างวิธีการอื่นที่ใช้พารามิเตอร์ความกว้างและความสูงสูงสุด

สมมติว่าคุณมี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];
}

1
นี่เป็นสิ่งที่ดีที่สุด แต่มันจะคืนค่าเป็นสองเท่าของขนาดที่ฉันกำหนดไว้เสมอ
Mashhadi

2
หากคุณต้องการแค่ลดขนาดไม่ใช่การขยายขนาดอย่าลืมเริ่มต้น imageWithImage: scaledToMaxWidth: maxHeight: method with: if (image.size.width <width && image.size.height <height) {return image; }
Arjan

5
min(ratioX, ratioY)เพื่อให้พอดีกับความกว้างสูงสุดและความสูงสูงสุดคุณจำเป็นต้องมีอัตราส่วนต่ำสุดเป็นปัจจัยขนาด: มิฉะนั้นหากความกว้างมากกว่านั้นอาจไม่พอดีกับความสูงสูงสุด
Jason Sturges

ImageUtilities มันอยู่ที่ไหน?
ทอง

44

คำตอบที่ดีที่สุด 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!
}

39

ขอบคุณ @ 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
}

18

วิธีนี้เป็นหมวดหมู่บน 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

2
พบว่าสิ่งนี้ให้ผลลัพธ์ที่ดีที่สุดสำหรับฉันด้วยขนาดหน่วยความจำที่เล็กที่สุด +1
Tommie C.

12

เวอร์ชันSwift 5ของความยาวพอดีกับความสูงอ้างอิงจากคำตอบของ @ János

ใช้UIGraphicsImageRendererAPI ที่ทันสมัยดังนั้นการ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 (แบบเวกเตอร์) เพื่อรักษาคุณภาพในทุกขนาดการเรนเดอร์


7

วิธีที่ง่ายที่สุดคือตั้งค่าเฟรมของคุณ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 แต่เขาคงต้องการที่จะปรับให้พอดีกับ [สำเนาของ] UIImage โดยตรงซึ่งเป็นสิ่งที่มีประโยชน์มากเมื่อคุณทำงาน CoreGraphics
Womble

6

โดยทางโปรแกรม:

imageView.contentMode = UIViewContentModeScaleAspectFit;

สตอรี่บอร์ด:

ป้อนคำอธิบายภาพที่นี่


มันใช้งานได้ แต่ลดรอยเท้าของหน่วยความจำคุณสามารถทำให้แอปทำงานได้เร็วขึ้นเช่นโหลดภาพขนาดย่อจำนวนมาก
ingconti

นั่นคือ UIImageView ไม่ใช่ UIImage บางครั้งคุณต้องวาดโดยไม่ใช้ UIImageView
Womble

5

เรามีคำตอบที่ดีสองสามข้อสำหรับการปรับขนาดภาพ แต่ฉันแค่แก้ไขตามความต้องการของฉัน หวังว่านี่จะช่วยคนอย่างฉัน

ความต้องการของฉันคือ

  1. หากความกว้างของภาพมากกว่า 1920 ให้ปรับขนาดด้วยความกว้าง 1920 และรักษาความสูงด้วยอัตราส่วนภาพต้นฉบับ
  2. หากความสูงของภาพมากกว่า 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สำหรับการปรับขนาดฉันได้ใช้วิธีของเขา

คุณอาจต้องการตรวจสอบสิ่งนี้ด้วยสำหรับการคำนวณการปรับขนาด


4

เพียงแค่นำเข้า AVFoundation และใช้งาน AVMakeRectWithAspectRatioInsideRect(CGRectCurrentSize, CGRectMake(0, 0, YOUR_WIDTH, CGFLOAT_MAX)


2

เพื่อปรับปรุงคำตอบของ 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
    }
}

เมื่อตั้งค่ามาตราส่วนเป็น 0.0 จะใช้มาตราส่วนของหน้าจอหลักซึ่งสำหรับจอภาพ Retina คือ 2.0 หรือสูงกว่า (3.0 บน iPhone 6 Plus)


1

Ryan's Solution @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);
}

1

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

1

Zeeshan Tufail และ Womble ตอบโจทย์ในSwift 5พร้อมการปรับปรุงเล็กน้อย ที่นี่เรามีส่วนขยายที่มี 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)
    }
}

0

อันนี้เหมาะสำหรับฉัน รักษาอัตราส่วนและใช้ขนาด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;
}

0

คำนวณความสูงที่ดีที่สุดของรูปภาพสำหรับความกว้างที่มี

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

0

หากใครต้องการโซลูชันนี้ใน 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
}

-1

ฉันได้แก้ไขด้วยวิธีที่ง่ายกว่ามาก

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

ตัวคูณของสเกลจะกำหนดการสเกลของภาพยิ่งตัวคูณมีขนาดเล็กลง คุณจึงสามารถตรวจสอบสิ่งที่เหมาะกับหน้าจอของคุณ

หรือคุณสามารถรับตัวคูณได้ด้วยการหาร imagewidth / screenwidth

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.