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.

Melati
sumber

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;
}
Maverick1st
sumber
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];
}
Ryan
sumber
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!
}
Alessandro Ornano
sumber
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
}
János
sumber
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
mohamede1945
sumber
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.

Womble
sumber
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;
}
Srikar Appalaraju
sumber
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

Mona
sumber
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.

swiftBoy
sumber
4

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

mariusLAN
sumber
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];
    }
TheCodingArt
sumber
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).

oscarr
sumber
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);
}
Daniel Krom
sumber
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
    }
}
Eridana
sumber
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)
    }
}
Dmih
sumber
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;
}
Zeeshan Tufail
sumber
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
    }
}
AshvinGudaliya
sumber
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
}
anagarD
sumber
-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.

Siddhant Saxena
sumber