Zmień rozmiar UIImage na 200x200pt / px


83

Zmagałem się ze zmianą rozmiaru obrazu. Zasadniczo natknąłem się na: jak zmniejszyć UIImage i sprawić, by był jednocześnie chrupiący / ostry zamiast rozmazanego?

Wydaje się, że jest to uzasadnione rozwiązanie, ale w jakiś sposób nie działa poprawnie.

Moja aplikacja obsługuje zdjęcia z rolki aparatu. Te zdjęcia powinny być zmniejszone do około 200x200, przy czym ważna jest szerokość, a nie wysokość.

Niestety, nie mam przykładowego kodu, ponieważ wyrzuciłem go z wściekłości na niedziałające rozwiązanie, przepraszam.


Co dokładnie nie działa poprawnie? Jakiego wyniku oczekujesz i jaki wynik uzyskałeś?
ifau

oczekuję obrazu o szerokości 200 i przy tym stosunku wysokości x. Nadal otrzymuję oryginalny obraz, taki jak 1920x ... cokolwiek
swift_dan

Odpowiedzi:


150

Oto mój kod. Obraz ma szerokość 850 pikseli, a nie 200 pikseli:

 func resizeImage(image: UIImage, newWidth: CGFloat) -> UIImage {

    let scale = newWidth / image.size.width
    let newHeight = image.size.height * scale
    UIGraphicsBeginImageContext(CGSizeMake(newWidth, newHeight))
    image.drawInRect(CGRectMake(0, 0, newWidth, newHeight))
    let newImage = UIGraphicsGetImageFromCurrentImageContext()
    UIGraphicsEndImageContext()

    return newImage
}


@IBAction func chooseImage(sender: AnyObject) {


    var myPickerController = UIImagePickerController()
    myPickerController.sourceType = UIImagePickerControllerSourceType.PhotoLibrary
    myPickerController.delegate = self;
    self.presentViewController(myPickerController, animated: true, completion: nil)


}

func imagePickerController(picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [NSObject : AnyObject])

{
    var imagenow = info[UIImagePickerControllerOriginalImage] as? UIImage

    imageImage.image = resizeImage(imagenow!, newWidth: 200)



    pimg2 = imageImage.image!

    cidnew2 = textFieldCID!.text!
    pname2 = textFieldName!.text
    pmanu2 = textFieldMan!.text
    pnick2 = textFieldNick!.text
    podate2 = textFieldPODate!.text
    pno2 = textFieldArtNo!.text



    self.dismissViewControllerAnimated(true, completion: nil)

}

1
aby pozbyć się błędów w swift 3, mogą pomóc informacje podane na stackoverflow.com/a/37948158/1404324
Faruk,

3
praca w szybkim 4: func resizeImage(image: UIImage, newWidth: CGFloat) -> UIImage { let scale = newWidth / image.size.width let newHeight = image.size.height * 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! }
mikey9

65

Na podstawie odpowiedzi swift_dan, aktualizacja dla Swift 3

func resizeImage(image: UIImage, newWidth: CGFloat) -> UIImage? {

    let scale = newWidth / image.size.width
    let newHeight = image.size.height * 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
}

2
Jeśli chcesz zachować jakość wyświetlaczy siatkówki i zachować przezroczystość, użyj: UIGraphicsBeginImageContextWithOptions (CGSize (width: newWidth, height: newHeight), false, 0)
Evgeny Karev

Zmniejszyło to mój obraz z 18 MB do <1 MB! Użyłem: resizeImage (image: (info [UIImagePickerControllerOriginalImage] as? UIImage) !, newWidth: 200) na iPadzie 9,7 ". Obraz pochodzi z imagePickerController. Używanie swift 3.0
Brian

43

Jeśli masz do czynienia z obrazami PNG, które zawierają przezroczystości, zaakceptowana funkcja odpowiedzi faktycznie konwertuje przezroczyste obszary na czarne.

Jeśli chcesz skalować i zachować folie na miejscu, wypróbuj tę funkcję:

SWIFT 4

extension UIImage {
    func scaleImage(toSize newSize: CGSize) -> UIImage? {
        var newImage: UIImage?
        let newRect = CGRect(x: 0, y: 0, width: newSize.width, height: newSize.height).integral
        UIGraphicsBeginImageContextWithOptions(newSize, false, 0)
        if let context = UIGraphicsGetCurrentContext(), let cgImage = self.cgImage {
            context.interpolationQuality = .high
            let flipVertical = CGAffineTransform(a: 1, b: 0, c: 0, d: -1, tx: 0, ty: newSize.height)
            context.concatenate(flipVertical)
            context.draw(cgImage, in: newRect)
            if let img = context.makeImage() {
                newImage = UIImage(cgImage: img)
            }
            UIGraphicsEndImageContext()
        }
        return newImage
    }
}

1
Niesamowite… zmniejszono ślad pamięci z poniżej 200 MB do 18: D
Tom

3
Powinieneś także wziąć pod uwagę skalę ekranu, zastępując init UIImage przez:let scale = UIScreen.main.scale let newImage = UIImage(cgImage: context.makeImage()!, scale: scale, orientation: .up)
picciano

1
% 30 użytkowników ulega awarii w tej funkcji .. at line context.draw (self.cgImage !, in: newRect) ... Crashed: com.apple.root.utility-qos 0x1001500a8 wyspecjalizowany UIImage.scaleImage (toSize: CGSize) - > UIImage?
Czy Aksoy

1
Dziękuję @CanAksoy, usunąłem wymuszone opcje, to powinno pomóc.
Travis M.,

21

Dla Swift 3.0

po prostu dodaj ten fragment jako rozszerzenie do UIImage. Należy jednak pamiętać, że obraz nie będzie miał kwadratowej formy, ale jeśli był w takiej formie, to wynik będzie kwadratowy.

extension UIImage {
    func resizeImage(newWidth: CGFloat) -> UIImage {

        let scale = newWidth / self.size.width
        let newHeight = self.size.height * scale
        UIGraphicsBeginImageContext(CGSize(width: newWidth, height: newHeight))
        self.draw(in: CGRect(x: 0, y: 0, width: newWidth, height: newHeight))
        let newImage = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()

        return newImage!
    } }

Wypróbowałem ten kod. Generuje mały obraz ;; er, ale pozostawia duży wydruk pamięci - przydziela dodatkowe 100-200 MB na stercie ((
rommex

10

Swift 4.0 -

Jeśli masz do czynienia z obrazami zawierającymi przezroczystość, zaakceptowana funkcja odpowiedzi faktycznie przekształci przezroczyste obszary na czarne.

Jeśli chcesz skalować i zachować folie na miejscu, wypróbuj tę funkcję:

func resizeImageWith(image: UIImage, newSize: CGSize) -> UIImage {

    let horizontalRatio = newSize.width / image.size.width
    let verticalRatio = newSize.height / image.size.height

    let ratio = max(horizontalRatio, verticalRatio)
    let newSize = CGSize(width: image.size.width * ratio, height: image.size.height * ratio)
    var newImage: UIImage

    if #available(iOS 10.0, *) {
        let renderFormat = UIGraphicsImageRendererFormat.default()
        renderFormat.opaque = false
        let renderer = UIGraphicsImageRenderer(size: CGSize(width: newSize.width, height: newSize.height), format: renderFormat)
        newImage = renderer.image {
            (context) in
            image.draw(in: CGRect(x: 0, y: 0, width: newSize.width, height: newSize.height))
        }
    } else {
        UIGraphicsBeginImageContextWithOptions(CGSize(width: newSize.width, height: newSize.height), isOpaque, 0)
        image.draw(in: CGRect(x: 0, y: 0, width: newSize.width, height: newSize.height))
        newImage = UIGraphicsGetImageFromCurrentImageContext()!
        UIGraphicsEndImageContext()
    }

    return newImage
}

8

Ten kod wykorzystuje UIGraphicsImageRenderer wprowadzony w iOS 10: w moich testach był o 10-40% szybszy niż wcześniejsze próbki z UIGraphicsBeginImageContext (Swift 4 / Xcode 9):

extension UIImage {
        func renderResizedImage (newWidth: CGFloat) -> UIImage {
            let scale = newWidth / self.size.width
            let newHeight = self.size.height * scale
            let newSize = CGSize(width: newWidth, height: newHeight)

            let renderer = UIGraphicsImageRenderer(size: newSize)

            let image = renderer.image { (context) in
                self.draw(in: CGRect(origin: CGPoint(x: 0, y: 0), size: newSize))
            }
            return image
        }
    }

Jest już odpowiedź na to pytanie: stackoverflow.com/a/45936836/1489885
MA

1
@ MA mój kod jest krótszy, jest wykonany z rozszerzeniem i zawiera moje dane dotyczące wydajności.
rommex

Chociaż bardzo podobała mi się ta odpowiedź (za używanie nowoczesnych narzędzi, szybkie i zwięzłe kodowanie), muszę zwrócić uwagę na nieoczekiwane zachowanie, którego przy niej doświadczyłem. Jeśli oryginalny UIImage jest wykadrowany z aparatu i ma pewien rozmiar (powiedzmy 1180x850), a ja prosiłem kod o „przeskalowanie go w dół” do newWidth: 800, to faktycznie WYKLASŁO rozmiar obrazu - ponieważ moje urządzenie miało 3x siatkówkę !! ! NALEŻY dostarczyć UIGraphicsImageRendererFormat z żądaną skalą !!! Strzec się. Dostaliśmy duży obraz zamiast mniejszego.
Motti Shneor

7

Ta funkcja zwróci obraz o określonej szerokości :

func scaleImage(image: UIImage, maximumWidth: CGFloat) -> UIImage {
    let rect: CGRect = CGRectMake(0, 0, image.size.width, image.size.height)
    let cgImage: CGImageRef = CGImageCreateWithImageInRect(image.CGImage!, rect)!
    return UIImage(CGImage: cgImage, scale: image.size.width / maximumWidth, orientation: image.imageOrientation)
}

Swift 3.0

func scaledImage(_ image: UIImage, maximumWidth: CGFloat) -> UIImage {
    let rect: CGRect = CGRect(x: 0, y: 0, width: image.size.width, height: image.size.height)
    let cgImage: CGImage = image.cgImage!.cropping(to: rect)!
    return UIImage(cgImage: cgImage, scale: image.size.width / maximumWidth, orientation: image.imageOrientation)
}

4

Dalsze ulepszanie odpowiedzi @rommex przy użyciu maksymalnego rozmiaru w Swift 4.2:

private extension UIImage {
    func scaled(to maxSize: CGFloat) -> UIImage? {
        let aspectRatio: CGFloat = min(maxSize / size.width, maxSize / size.height)
        let newSize = CGSize(width: size.width * aspectRatio, height: size.height * aspectRatio)
        let renderer = UIGraphicsImageRenderer(size: newSize)
        return renderer.image { context in
            draw(in: CGRect(origin: CGPoint(x: 0, y: 0), size: newSize))
        }
    }
}

3

Ten kod działa doskonale na kwadratowym obrazie i nie traci jakości

extension UIImage {

func resize(targetSize: CGSize) -> UIImage {
    return UIGraphicsImageRenderer(size:targetSize).image { _ in
        self.draw(in: CGRect(origin: .zero, size: targetSize))
    }
}

}

Odpowiedź od: Zmień rozmiar obrazu bez utraty jakości


2

Jeśli używasz Kingfisher lib do ładowania obrazów w swoim projekcie i chcesz zmienić jego rozmiar, oto sposób:

  • Xcode 8
  • Szybki 3x

    let imageUrl = URL(string: "your image url")
     //Size refer to the size which you want to resize your original image
     let size = CGSize(width: 60, height: 60)
     let processImage = ResizingImageProcessor(targetSize: size, contentMode: .aspectFit)
     cell.courseTitleImage.kf.setImage(with: imageUrl! , placeholder: UIImage(named: "placeholder"), options: [.transition(ImageTransition.fade(1)), .processor(processImage)], progressBlock: nil, completionHandler: nil)
    

    LUB

    Zmień rozmiar obrazu lokalnego: - możesz odwołać się do odpowiedzi @Christoph R.


  • 1
    func getScaledDimension(width: CGFloat, height: CGFloat,new_width: CGFloat, new_height: CGFloat)->CGPoint {
    
            let widthAspect =  (width / new_width)
            let heightAspect = (height / new_height)
            if widthAspect == 0 || heightAspect == 0 {
                return CGPoint(x: width, y: height)
            }
            var width1 : CGFloat = 0
            var height1 : CGFloat =  0
            if widthAspect > heightAspect {
                width1 = (width) / heightAspect
                height1 = (height) / heightAspect
            } else {
                width1 = (width) / widthAspect
                height1 = (height) / widthAspect
            }
    
            return CGPoint(x: width1, y: height1 )
        }
    
    
    
        func ResizeImage(image: UIImage, targetSize: CGSize) -> UIImage {
    
            let rect = CGRectMake(0, 0, targetSize.width, targetSize.height)
    
            UIGraphicsBeginImageContextWithOptions(targetSize, false, 1.0)
            image.drawInRect(rect)
            let newImage = UIGraphicsGetImageFromCurrentImageContext()
            UIGraphicsEndImageContext()
    
            return newImage
        }
    
    
     let imagesize =  getScaledDimension(image.size.width, height: image.size.height , new_width: Width, new_height: Hieght)
    
            print("Image Size Scaled Dimension -> H:\(imagesize.x) W:\(imagesize.y)")
    
            let newImage = ResizeImage(image, targetSize: CGSizeMake(imagesize.x,imagesize.y))
            print("Resize Image Size -> H\(newImage.size.height) W\(newImage.size.width) ")
    

    1

    To jest kontynuacja odpowiedzi @Christoph R opublikowanej dla Swift 3.0. Ten kod działa dla Swift 5.0.1.

    static func resizeImage(image: UIImage, newWidth: CGFloat) -> UIImage {
    
        let scale = newWidth / image.size.width
        let newHeight = image.size.height * 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!
    }
    

    w witrynie dzwoniącego

    TaskUtilties.resizeImage(image: rawImage!, newWidth: CGFloat(50))
    

    0

    Zmniejsz rozmiar obrazu o 1024, zawsze możesz przekonwertować zgodnie z pojemnością serwera

    func resizeImage(image: UIImage) -> UIImage {
    
            if image.size.height >= 1024 && image.size.width >= 1024 {
    
                UIGraphicsBeginImageContext(CGSize(width:1024, height:1024))
                image.draw(in: CGRect(x:0, y:0, width:1024, height:1024))
    
                let newImage = UIGraphicsGetImageFromCurrentImageContext()
                UIGraphicsEndImageContext()
    
                return newImage!
    
            }
            else if image.size.height >= 1024 && image.size.width < 1024
            {
    
                UIGraphicsBeginImageContext(CGSize(width:image.size.width, height:1024))
                image.draw(in: CGRect(x:0, y:0, width:image.size.width, height:1024))
    
                let newImage = UIGraphicsGetImageFromCurrentImageContext()
                UIGraphicsEndImageContext()
    
                return newImage!
    
            }
            else if image.size.width >= 1024 && image.size.height < 1024
            {
    
                UIGraphicsBeginImageContext(CGSize(width:1024, height:image.size.height))
                image.draw(in: CGRect(x:0, y:0, width:1024, height:image.size.height))
    
                let newImage = UIGraphicsGetImageFromCurrentImageContext()
                UIGraphicsEndImageContext()
    
                return newImage!
    
            }
            else
            {
                return image
            }
    
        }
    
    Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
    Licensed under cc by-sa 3.0 with attribution required.