Ubah ukuran UIImage dengan mempertahankan rasio Aspek dan lebar


138

Saya melihat di banyak posting untuk mengubah ukuran gambar dengan menjaga rasio aspek. Fungsi ini menggunakan titik tetap (Lebar dan Tinggi) untuk RECT saat mengubah ukuran. Tetapi dalam proyek saya, saya perlu mengubah ukuran tampilan berdasarkan Lebar saja, Tinggi harus diambil secara otomatis berdasarkan rasio aspek. ada yang membantu saya untuk mencapai ini.

Jawaban:


230

Metode Srikar bekerja dengan sangat baik, jika Anda mengetahui tinggi dan lebar Ukuran baru Anda. Jika Anda misalnya hanya mengetahui lebar yang ingin Anda skalakan dan tidak peduli dengan tingginya, Anda harus menghitung faktor skala ketinggian terlebih dahulu.

+(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
Anda tidak benar-benar membutuhkan newWidthvariabel di sini, itu sudah i_width.
MLQ

2
Anda juga perlu membagi menurut tinggi dan membandingkan faktor penskalaan menggunakan mana saja yang mendekati 0. kode di atas hanya akan berfungsi dengan gambar yang lebih lebar daripada yang tingginya
IceForge

1
Saya hanya perlu membagi dengan tinggi jika saya ingin mengetahui rasio tinggi saya juga dan menyesuaikannya dengan menskalakan lebar atau tinggi. tetapi karena TO meminta secara eksplisit untuk menjaga rasio dan lebar, dan bukan lebar atau tinggi, jawaban saya sepenuhnya benar.
Maverick1st

12
Jawaban yang bagus, terima kasih. Satu hal lagi: jika Anda mengalami penurunan kualitas gambar menggunakan metode ini kemudian menggunakan UIGraphicsBeginImageContextWithOptions(CGSizeMake(newWidth, newHeight), NO, 0);ketimbangUIGraphicsBeginImageContext(CGSizeMake(newWidth, newHeight));
skornos

57

Jika Anda tidak mengetahui apakah gambar akan menjadi potret atau lanskap (misalnya pengguna mengambil gambar dengan kamera), saya membuat metode lain yang mengambil parameter lebar dan tinggi maks.

Katakanlah Anda memiliki rasio UIImage *myLargeImageyang 4: 3.

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

UIImage yang diubah ukurannya akan menjadi 1024x768 jika lanskap; 768x1024 jika potret. Metode ini juga akan menghasilkan gambar beresolusi lebih tinggi untuk tampilan retina.

+ (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
Ini adalah hal terbaik tetapi selalu mengembalikan dua kali lipat dari ukuran yang saya tentukan
Mashhadi

2
Jika Anda hanya ingin melakukan downsizing, bukan upsizing, jangan lupa untuk memulai imageWithImage: scaledToMaxWidth: maxHeight: metode dengan: if (image.size.width <width && image.size.height <height) {return image; }
Arjan

5
Untuk muat dalam lebar max dan tinggi max, Anda perlu rasio minimum sebagai faktor skala: min(ratioX, ratioY). Sebaliknya, jika lebarnya lebih besar, mungkin tidak sesuai dengan tinggi maksimal.
Jason Sturges

ImageUtilities di mana itu?
tong

44

Jawaban terbaik Maverick 1st diterjemahkan dengan benar ke Swift (bekerja dengan swift 3 terbaru ):

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

terima kasih @ Maverick1st algoritma, saya menerapkannya Swift, dalam kasus saya tinggi adalah parameter input

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

Metode ini adalah kategori di UIImage. Apakah skala agar sesuai dengan beberapa baris kode menggunakan AVFoundation. Jangan lupa untuk mengimpor #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
Menemukan ini untuk memberikan hasil terbaik bagi saya dengan jejak memori terkecil. +1
Tommie C.

12

Swift 5 versi aspek-fit-to- height , berdasarkan jawaban oleh @ János

Menggunakan UIGraphicsImageRendererAPI modern , sehingga valid UIImagedijamin akan kembali.

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

Anda dapat menggunakan ini bersama dengan aset gambar PDF (berbasis vektor), untuk menjaga kualitas pada ukuran render apa pun.


7

Cara paling sederhana adalah mengatur bingkai Anda UIImageViewdan mengatur contentModeke salah satu opsi pengubahan ukuran.

Kode berjalan seperti ini - Ini dapat digunakan sebagai metode utilitas -

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

Ingatlah bahwa OP tidak menyebutkan UIImageView. Sebaliknya, dia mungkin ingin menyesuaikan aspek [salinan] UIImage secara langsung, yang merupakan hal yang sangat berguna untuk dimiliki saat Anda melakukan pekerjaan CoreGraphics.
Womble

6

Secara terprogram:

imageView.contentMode = UIViewContentModeScaleAspectFit;

Papan cerita:

masukkan deskripsi gambar di sini


berfungsi, TAPI mengurangi jejak memori, Anda dapat membuat aplikasi bekerja lebih cepat, misalnya memuat banyak thumbnail.
ingconti

Itu adalah UIImageView, bukan UIImage. Terkadang, Anda perlu menggambar tanpa UIImageView.
Womble

5

Nah, kami memiliki beberapa jawaban bagus di sini untuk mengubah ukuran gambar, tetapi saya hanya memodifikasi sesuai kebutuhan saya. Semoga ini membantu seseorang seperti saya.

Persyaratan saya adalah

  1. Jika lebar gambar lebih dari 1920, ubah ukurannya dengan lebar 1920 dan pertahankan tinggi dengan rasio aspek asli.
  2. Jika tinggi gambar lebih dari 1080, ubah ukurannya dengan tinggi 1080 dan pertahankan lebar dengan rasio aspek asli.

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

Terima kasih kepada @ Srikar Appal , untuk mengubah ukuran saya telah menggunakan metodenya.

Anda mungkin ingin memeriksa ini juga untuk perhitungan resize.


4

Cukup impor AVFoundation dan gunakan AVMakeRectWithAspectRatioInsideRect(CGRectCurrentSize, CGRectMake(0, 0, YOUR_WIDTH, CGFLOAT_MAX)


2

Untuk memperbaiki jawaban 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
    }
}

Saat skala diatur ke 0,0, faktor skala layar utama digunakan, yang untuk tampilan Retina adalah 2.0 atau lebih tinggi (3.0 di iPhone 6 Plus).


1

Solusi Ryan @Ryan dalam kode cepat

menggunakan:

 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

Di Swift 3 ada beberapa perubahan. Berikut adalah ekstensi untuk 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 dan Womble menjawab di Swift 5 dengan sedikit peningkatan. Di sini kami memiliki ekstensi dengan 2 fungsi untuk menskalakan gambar ke maxLengthdimensi apa pun dan kompresi 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

Yang ini sempurna untukku. Mempertahankan rasio aspek dan membutuhkan file maxLength. Lebar atau Tinggi tidak akan lebih darimaxLength

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

Menghitung tinggi gambar terbaik untuk lebar yang tersedia.

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

Jika seseorang membutuhkan solusi ini di 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

Saya telah menyelesaikannya dengan cara yang jauh lebih sederhana

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

multiplier skala akan menentukan scalling gambar, semakin banyak multiplier semakin kecil gambar. sehingga Anda dapat memeriksa apa yang cocok dengan layar Anda.

Atau Anda juga bisa mendapatkan pengali dengan membagi imagewidth / screenwidth.

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.