Jak zmienić rozmiar obrazu w Swift?

94

Tworzę aplikację na iOS, używając Swift i Parse.com

Próbuję pozwolić użytkownikowi wybrać zdjęcie z selektora obrazów, a następnie zmienić rozmiar wybranego obrazu na 200x200 pikseli przed przesłaniem go do mojego zaplecza.

Parse.com ma samouczek dla aplikacji do kopiowania na Instagramie o nazwie „AnyPic”, który zawiera kod do zmiany rozmiaru obrazów, ale jest w Objective-C ....

// Resize the image to be square (what is shown in the preview)
UIImage *resizedImage = [anImage resizedImageWithContentMode:UIViewContentModeScaleAspectFit
        bounds:CGSizeMake(560.0f, 560.0f)
        interpolationQuality:kCGInterpolationHigh];
// Create a thumbnail and add a corner radius for use in table views
UIImage *thumbnailImage = [anImage thumbnailImage:86.0f
        transparentBorder:0.0f
        cornerRadius:10.0f
        interpolationQuality:kCGInterpolationDefault];

Jak utworzyć wersję 200x200px wybranego obrazu (do przesłania) w Swift?

A co robi funkcja thumbnailImage?

Maks
źródło

Odpowiedzi:

206

Zobacz mój wpis na blogu, Zmień rozmiar obrazu w szybkim i obiektywnym C , aby uzyskać więcej informacji.

Funkcja zmiany rozmiaru obrazu w szybkim tempie, jak poniżej.

func resizeImage(image: UIImage, targetSize: CGSize) -> UIImage {
    let size = image.size

    let widthRatio  = targetSize.width  / size.width
    let heightRatio = targetSize.height / size.height

    // Figure out what our orientation is, and use that to form the rectangle
    var newSize: CGSize
    if(widthRatio > heightRatio) {
        newSize = CGSizeMake(size.width * heightRatio, size.height * heightRatio)
    } else {
        newSize = CGSizeMake(size.width * widthRatio,  size.height * widthRatio)
    }

    // This is the rect that we've calculated out and this is what is actually used below
    let rect = CGRectMake(0, 0, newSize.width, newSize.height)

    // Actually do the resizing to the rect using the ImageContext stuff
    UIGraphicsBeginImageContextWithOptions(newSize, false, 1.0)
    image.drawInRect(rect)
    let newImage = UIGraphicsGetImageFromCurrentImageContext()
    UIGraphicsEndImageContext()

    return newImage
}

Użyj powyższej funkcji i zmień rozmiar obrazu za pomocą 200 * 200, jak poniżej

self.resizeImage(UIImage(named: "yourImageName")!, targetSize: CGSizeMake(200.0, 200.0))

aktualizacja swift3

 func resizeImage(image: UIImage, targetSize: CGSize) -> UIImage {
    let size = image.size

    let widthRatio  = targetSize.width  / size.width
    let heightRatio = targetSize.height / size.height

    // Figure out what our orientation is, and use that to form the rectangle
    var newSize: CGSize
    if(widthRatio > heightRatio) {
        newSize = CGSize(width: size.width * heightRatio, height: size.height * heightRatio)
    } else {
        newSize = CGSize(width: size.width * widthRatio,  height: size.height * widthRatio)
    }

    // This is the rect that we've calculated out and this is what is actually used below
    let rect = CGRect(x: 0, y: 0, width: newSize.width, height: newSize.height)

    // Actually do the resizing to the rect using the ImageContext stuff
    UIGraphicsBeginImageContextWithOptions(newSize, false, 1.0)
    image.draw(in: rect)
    let newImage = UIGraphicsGetImageFromCurrentImageContext()
    UIGraphicsEndImageContext()

    return newImage!
}
Kirit Modi
źródło
Rozmiar docelowy można przekazać bezpośrednio w UIGraphicsBeginImageContextWithOptions (targetSize, false, 1.0).
Kirit Modi,
2
zwykle chcesz, aby UIGraphicsBeginImageContextWithOptionsostatni parametr był, 0.0ponieważ będzie to nam skala urządzenia.
vikingosegundo
Możesz nieco uprościć obliczenia, używając AVMakeRect w AVFoundation. Utwórz targetRect z początkiem (0,0) i rozmiarem targetSize, a następnie rect = AVMakeRect (aspektRatio: image.size, insideRect: targetRect)
Dale
1
Możesz poprawić jakość podczas skalowania w górę, ustawiając jakość interpolacji w kontekście graficznym UIGraphicsGetCurrentContext () ?. interpolationQuality = .high
Dale
5
Jeśli otrzymujesz komunikat „GCSizeMake jest niedostępny w Swift”, użyj CGSize (szerokość: 200,0, wysokość: 200,0)
Islam Abdalla
38

Dla Swift 4.0 i iOS 10

    extension UIImage {
        func resizeImage(_ dimension: CGFloat, opaque: Bool, contentMode: UIViewContentMode = .scaleAspectFit) -> UIImage {
            var width: CGFloat
            var height: CGFloat
            var newImage: UIImage

            let size = self.size
            let aspectRatio =  size.width/size.height

            switch contentMode {
                case .scaleAspectFit:
                    if aspectRatio > 1 {                            // Landscape image
                        width = dimension
                        height = dimension / aspectRatio
                    } else {                                        // Portrait image
                        height = dimension
                        width = dimension * aspectRatio
                    }

            default:
                fatalError("UIIMage.resizeToFit(): FATAL: Unimplemented ContentMode")
            }

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

            return newImage
        }
    }
Eng Yew
źródło
Jak nazwałbym tę funkcję?
ICT1901
2
@DavidDelMonte możesz wywołać tę metodę na obiekcie UIImage. myImage.resizeImage(...).
Aweda,
W jaki sposób zmienia się rozmiar tych obrazów? Jakie metody interpolacji są używane? Czy możesz wybrać metody interpolacji?
Moondra,
32

Ponieważ odpowiedź @KiritModi pochodzi z 2015 roku, jest to wersja Swift 3.0:

func resizeImage(image: UIImage, targetSize: CGSize) -> UIImage {
    let size = image.size

    let widthRatio  = targetSize.width  / image.size.width
    let heightRatio = targetSize.height / image.size.height

    // Figure out what our orientation is, and use that to form the rectangle
    var newSize: CGSize
    if(widthRatio > heightRatio) {
        newSize = CGSize(width: size.width * heightRatio, height: size.height * heightRatio)
    } else {
        newSize = CGSize(width: size.width * widthRatio,  height: size.height * widthRatio)
    }

    // This is the rect that we've calculated out and this is what is actually used below
    let rect = CGRect(x: 0, y: 0, width: newSize.width, height: newSize.height)

    // Actually do the resizing to the rect using the ImageContext stuff
    UIGraphicsBeginImageContextWithOptions(newSize, false, 1.0)
    image.draw(in: rect)
    let newImage = UIGraphicsGetImageFromCurrentImageContext()
    UIGraphicsEndImageContext()

    return newImage!
}
Rafael Ruiz Muñoz
źródło
i jak nazywasz tę funkcję na przykład?
Konstantinos Natsios
2
let thumbnail = resizeImage (image: fullsizeImage, CGSize.init (szerokość: 70, wysokość: 70))
arjavlad
2
Poleciłbym zastąpić 1.0 w skali przez UIScreen.main.scale, aby uniknąć rozmytych obrazów
PSchuette
W jaki sposób zmienia się rozmiar tych obrazów? Jakie metody interpolacji są używane? Czy możesz wybrać metody interpolacji?
Moondra,
23

W przypadku Swift 4 po prostu zrobiłbym rozszerzenie UIImage z odniesieniem do siebie.

import UIKit
extension UIImage {
  func resizeImage(targetSize: CGSize) -> UIImage {
    let size = self.size
    let widthRatio  = targetSize.width  / size.width
    let heightRatio = targetSize.height / size.height
    let newSize = widthRatio > heightRatio ?  CGSize(width: size.width * heightRatio, height: size.height * heightRatio) : CGSize(width: size.width * widthRatio,  height: size.height * widthRatio)
    let rect = CGRect(x: 0, y: 0, width: newSize.width, height: newSize.height)

    UIGraphicsBeginImageContextWithOptions(newSize, false, 1.0)
    self.draw(in: rect)
    let newImage = UIGraphicsGetImageFromCurrentImageContext()
    UIGraphicsEndImageContext()

    return newImage!
  }
}
Pavle Mijatovic
źródło
21

Detale

  • Xcode 10.2.1 (10E1001), Swift 5

Spinki do mankietów

Rozwiązanie

import UIKit
import CoreGraphics
import Accelerate

extension UIImage {

    public enum ResizeFramework {
        case uikit, coreImage, coreGraphics, imageIO, accelerate
    }

    /// Resize image with ScaleAspectFit mode and given size.
    ///
    /// - Parameter dimension: width or length of the image output.
    /// - Parameter resizeFramework: Technique for image resizing: UIKit / CoreImage / CoreGraphics / ImageIO / Accelerate.
    /// - Returns: Resized image.

    func resizeWithScaleAspectFitMode(to dimension: CGFloat, resizeFramework: ResizeFramework = .coreGraphics) -> UIImage? {

        if max(size.width, size.height) <= dimension { return self }

        var newSize: CGSize!
        let aspectRatio = size.width/size.height

        if aspectRatio > 1 {
            // Landscape image
            newSize = CGSize(width: dimension, height: dimension / aspectRatio)
        } else {
            // Portrait image
            newSize = CGSize(width: dimension * aspectRatio, height: dimension)
        }

        return resize(to: newSize, with: resizeFramework)
    }

    /// Resize image from given size.
    ///
    /// - Parameter newSize: Size of the image output.
    /// - Parameter resizeFramework: Technique for image resizing: UIKit / CoreImage / CoreGraphics / ImageIO / Accelerate.
    /// - Returns: Resized image.
    public func resize(to newSize: CGSize, with resizeFramework: ResizeFramework = .coreGraphics) -> UIImage? {
        switch resizeFramework {
            case .uikit: return resizeWithUIKit(to: newSize)
            case .coreGraphics: return resizeWithCoreGraphics(to: newSize)
            case .coreImage: return resizeWithCoreImage(to: newSize)
            case .imageIO: return resizeWithImageIO(to: newSize)
            case .accelerate: return resizeWithAccelerate(to: newSize)
        }
    }

    // MARK: - UIKit

    /// Resize image from given size.
    ///
    /// - Parameter newSize: Size of the image output.
    /// - Returns: Resized image.
    private func resizeWithUIKit(to newSize: CGSize) -> UIImage? {
        UIGraphicsBeginImageContextWithOptions(newSize, true, 1.0)
        self.draw(in: CGRect(origin: .zero, size: newSize))
        defer { UIGraphicsEndImageContext() }
        return UIGraphicsGetImageFromCurrentImageContext()
    }

    // MARK: - CoreImage

    /// Resize CI image from given size.
    ///
    /// - Parameter newSize: Size of the image output.
    /// - Returns: Resized image.
    // https://developer.apple.com/library/archive/documentation/GraphicsImaging/Reference/CoreImageFilterReference/index.html
    private func resizeWithCoreImage(to newSize: CGSize) -> UIImage? {
        guard let cgImage = cgImage, let filter = CIFilter(name: "CILanczosScaleTransform") else { return nil }

        let ciImage = CIImage(cgImage: cgImage)
        let scale = (Double)(newSize.width) / (Double)(ciImage.extent.size.width)

        filter.setValue(ciImage, forKey: kCIInputImageKey)
        filter.setValue(NSNumber(value:scale), forKey: kCIInputScaleKey)
        filter.setValue(1.0, forKey: kCIInputAspectRatioKey)
        guard let outputImage = filter.value(forKey: kCIOutputImageKey) as? CIImage else { return nil }
        let context = CIContext(options: [.useSoftwareRenderer: false])
        guard let resultCGImage = context.createCGImage(outputImage, from: outputImage.extent) else { return nil }
        return UIImage(cgImage: resultCGImage)
    }

    // MARK: - CoreGraphics

    /// Resize image from given size.
    ///
    /// - Parameter newSize: Size of the image output.
    /// - Returns: Resized image.
    private func resizeWithCoreGraphics(to newSize: CGSize) -> UIImage? {
        guard let cgImage = cgImage, let colorSpace = cgImage.colorSpace else { return nil }

        let width = Int(newSize.width)
        let height = Int(newSize.height)
        let bitsPerComponent = cgImage.bitsPerComponent
        let bytesPerRow = cgImage.bytesPerRow
        let bitmapInfo = cgImage.bitmapInfo

        guard let context = CGContext(data: nil, width: width, height: height,
                                      bitsPerComponent: bitsPerComponent,
                                      bytesPerRow: bytesPerRow, space: colorSpace,
                                      bitmapInfo: bitmapInfo.rawValue) else { return nil }
        context.interpolationQuality = .high
        let rect = CGRect(origin: CGPoint.zero, size: newSize)
        context.draw(cgImage, in: rect)

        return context.makeImage().flatMap { UIImage(cgImage: $0) }
    }

    // MARK: - ImageIO

    /// Resize image from given size.
    ///
    /// - Parameter newSize: Size of the image output.
    /// - Returns: Resized image.
    private func resizeWithImageIO(to newSize: CGSize) -> UIImage? {
        var resultImage = self

        guard let data = jpegData(compressionQuality: 1.0) else { return resultImage }
        let imageCFData = NSData(data: data) as CFData
        let options = [
            kCGImageSourceCreateThumbnailWithTransform: true,
            kCGImageSourceCreateThumbnailFromImageAlways: true,
            kCGImageSourceThumbnailMaxPixelSize: max(newSize.width, newSize.height)
            ] as CFDictionary
        guard   let source = CGImageSourceCreateWithData(imageCFData, nil),
                let imageReference = CGImageSourceCreateThumbnailAtIndex(source, 0, options) else { return resultImage }
        resultImage = UIImage(cgImage: imageReference)

        return resultImage
    }

    // MARK: - Accelerate

    /// Resize image from given size.
    ///
    /// - Parameter newSize: Size of the image output.
    /// - Returns: Resized image.
    private func resizeWithAccelerate(to newSize: CGSize) -> UIImage? {
        var resultImage = self

        guard let cgImage = cgImage, let colorSpace = cgImage.colorSpace else { return nil }

        // create a source buffer
        var format = vImage_CGImageFormat(bitsPerComponent: numericCast(cgImage.bitsPerComponent),
                                          bitsPerPixel: numericCast(cgImage.bitsPerPixel),
                                          colorSpace: Unmanaged.passUnretained(colorSpace),
                                          bitmapInfo: cgImage.bitmapInfo,
                                          version: 0,
                                          decode: nil,
                                          renderingIntent: .absoluteColorimetric)
        var sourceBuffer = vImage_Buffer()
        defer {
            sourceBuffer.data.deallocate()
        }

        var error = vImageBuffer_InitWithCGImage(&sourceBuffer, &format, nil, cgImage, numericCast(kvImageNoFlags))
        guard error == kvImageNoError else { return resultImage }

        // create a destination buffer
        let destWidth = Int(newSize.width)
        let destHeight = Int(newSize.height)
        let bytesPerPixel = cgImage.bitsPerPixel
        let destBytesPerRow = destWidth * bytesPerPixel
        let destData = UnsafeMutablePointer<UInt8>.allocate(capacity: destHeight * destBytesPerRow)
        defer {
            destData.deallocate()
        }
        var destBuffer = vImage_Buffer(data: destData, height: vImagePixelCount(destHeight), width: vImagePixelCount(destWidth), rowBytes: destBytesPerRow)

        // scale the image
        error = vImageScale_ARGB8888(&sourceBuffer, &destBuffer, nil, numericCast(kvImageHighQualityResampling))
        guard error == kvImageNoError else { return resultImage }

        // create a CGImage from vImage_Buffer
        let destCGImage = vImageCreateCGImageFromBuffer(&destBuffer, &format, nil, nil, numericCast(kvImageNoFlags), &error)?.takeRetainedValue()
        guard error == kvImageNoError else { return resultImage }

        // create a UIImage
        if let scaledImage = destCGImage.flatMap({ UIImage(cgImage: $0) }) {
            resultImage = scaledImage
        }

        return resultImage
    }
}

Stosowanie

Uzyskaj rozmiar obrazu

import UIKit

// https://stackoverflow.com/a/55765409/4488252
extension UIImage {
    func getFileSizeInfo(allowedUnits: ByteCountFormatter.Units = .useMB,
                         countStyle: ByteCountFormatter.CountStyle = .memory,
                         compressionQuality: CGFloat = 1.0) -> String? {
        // https://developer.apple.com/documentation/foundation/bytecountformatter
        let formatter = ByteCountFormatter()
        formatter.allowedUnits = allowedUnits
        formatter.countStyle = countStyle
        return getSizeInfo(formatter: formatter, compressionQuality: compressionQuality)
    }

    func getSizeInfo(formatter: ByteCountFormatter, compressionQuality: CGFloat = 1.0) -> String? {
        guard let imageData = jpegData(compressionQuality: compressionQuality) else { return nil }
        return formatter.string(fromByteCount: Int64(imageData.count))
    }
}

Funkcja testowa

private func test() {
    guard let img = UIImage(named: "img") else { return }
    printInfo(of: img, title: "original image |")
    let dimension: CGFloat = 2000

    var framework: UIImage.ResizeFramework = .accelerate
    var startTime = Date()
    if let img = img.resizeWithScaleAspectFitMode(to: dimension, resizeFramework: framework) {
        printInfo(of: img, title: "resized image |", with: framework, startedTime: startTime)
    }

    framework = .coreGraphics
    startTime = Date()
    if let img = img.resizeWithScaleAspectFitMode(to: dimension, resizeFramework: framework) {
        printInfo(of: img, title: "resized image |", with: framework, startedTime: startTime)
    }

    framework = .coreImage
    startTime = Date()
    if let img = img.resizeWithScaleAspectFitMode(to: dimension, resizeFramework: framework) {
        printInfo(of: img, title: "resized image |", with: framework, startedTime: startTime)
    }

    framework = .imageIO
    startTime = Date()
    if let img = img.resizeWithScaleAspectFitMode(to: dimension, resizeFramework: framework) {
        printInfo(of: img, title: "resized image |", with: framework, startedTime: startTime)
    }

    framework = .uikit
    startTime = Date()
    if let img = img.resizeWithScaleAspectFitMode(to: dimension, resizeFramework: framework) {
        printInfo(of: img, title: "resized image |", with: framework, startedTime: startTime)
    }
}

private func printInfo(of image: UIImage, title: String, with resizeFramework: UIImage.ResizeFramework? = nil, startedTime: Date? = nil) {
    var description = "\(title) \(image.size)"
    if let startedTime = startedTime { description += ", execution time: \(Date().timeIntervalSince(startedTime))" }
    if let fileSize = image.getFileSizeInfo(compressionQuality: 0.9) { description += ", size: \(fileSize)" }
    if let resizeFramework = resizeFramework { description += ", framework: \(resizeFramework)" }
    print(description)
}

Wynik

original image | (5790.0, 8687.0), size: 17.1 MB
resized image | (1333.0, 2000.0), execution time: 0.8192930221557617, size: 1.1 MB, framework: accelerate
resized image | (1333.0, 2000.0), execution time: 0.44696998596191406, size: 1 MB, framework: coreGraphics
resized image | (1334.0, 2000.0), execution time: 54.172922015190125, size: 1.1 MB, framework: coreImage
resized image | (1333.0, 2000.0), execution time: 1.8765920400619507, size: 1.1 MB, framework: imageIO
resized image | (1334.0, 2000.0), execution time: 0.4638739824295044, size: 1 MB, framework: uikit
Wasilij Bodnarczuk
źródło
na jakim urządzeniu został uruchomiony test?
Juan Boero
1
@JuanBoero IPhone 7 plus, iPhone X
Wasilij Bodnarchuk
19

Możliwe jest również użycie AlamofireImage ( https://github.com/Alamofire/AlamofireImage )

let size = CGSize(width: 30.0, height: 30.0)
let aspectScaledToFitImage = image.af_imageAspectScaled(toFit: size)

Funkcja w poprzednim poście dała mi rozmyty wynik.

Bas
źródło
1
Dzięki. W szybkich 3 self.yourimageview.sizeThatFits (size) działa.
BHAVIK PANCHAL
Oszczędź sobie czasu i nie używaj tego. Określony rozmiar jest oparty na skali urządzenia, a nie na żądanych pikselach: stackoverflow.com/questions/55930320/ ...
Alex Ritter
11

Wersja Swift 3 i styl rozszerzenia

Ta odpowiedź pochodzi od @Kirit Modi.

extension UIImage {

    func resizeImage(targetSize: CGSize) -> UIImage {
        let size = self.size

        let widthRatio  = targetSize.width  / size.width
        let heightRatio = targetSize.height / size.height

        // Figure out what our orientation is, and use that to form the rectangle
        var newSize: CGSize
        if(widthRatio > heightRatio) {
            newSize = CGSize(width: size.width * heightRatio, height: size.height * heightRatio)
        } else {
            newSize = CGSize(width: size.width * widthRatio,  height: size.height * widthRatio)
        }

        // This is the rect that we've calculated out and this is what is actually used below
        let rect = CGRect(x: 0, y: 0, width: newSize.width, height: newSize.height)

        // Actually do the resizing to the rect using the ImageContext stuff
        UIGraphicsBeginImageContextWithOptions(newSize, false, 1.0)
        self.draw(in: rect)
        let newImage = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()

        return newImage!
    }
}
Jerome
źródło
7

Dla Swift 5.0 i iOS 12

extension UIImage {
    func imageResized(to size: CGSize) -> UIImage {
        return UIGraphicsImageRenderer(size: size).image { _ in
            draw(in: CGRect(origin: .zero, size: size))
        }
    }
}

posługiwać się:

let image = #imageLiteral(resourceName: "ic_search")
cell!.search.image = image.imageResized(to: cell!.search.frame.size)
Azim Shaikh
źródło
6

Swift 4, wersja rozszerzona, BEZ BIAŁEJ LINII NA KRAWĘDZIACH.

Wydaje się, że nikt nie wspomina, że image.draw()wywołanie z wartościami niecałkowitymi może spowodować wyświetlenie artefaktu białej linii przy prawej lub dolnej krawędzi.

extension UIImage {

    func scaled(with scale: CGFloat) -> UIImage? {
        // size has to be integer, otherwise it could get white lines
        let size = CGSize(width: floor(self.size.width * scale), height: floor(self.size.height * scale))
        UIGraphicsBeginImageContext(size)
        draw(in: CGRect(x: 0, y: 0, width: size.width, height: size.height))
        let image = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        return image
    }
da1
źródło
5

Wersja Swift 4

extension UIImage {
    func resizeImage(_ newSize: CGSize) -> UIImage? {
        func isSameSize(_ newSize: CGSize) -> Bool {
            return size == newSize
        }

        func scaleImage(_ newSize: CGSize) -> UIImage? {
            func getScaledRect(_ newSize: CGSize) -> CGRect {
                let ratio   = max(newSize.width / size.width, newSize.height / size.height)
                let width   = size.width * ratio
                let height  = size.height * ratio
                return CGRect(x: 0, y: 0, width: width, height: height)
            }

            func _scaleImage(_ scaledRect: CGRect) -> UIImage? {
                UIGraphicsBeginImageContextWithOptions(scaledRect.size, false, 0.0);
                draw(in: scaledRect)
                let image = UIGraphicsGetImageFromCurrentImageContext() ?? UIImage()
                UIGraphicsEndImageContext()
                return image
            }
            return _scaleImage(getScaledRect(newSize))
        }

        return isSameSize(newSize) ? self : scaleImage(newSize)!
    }
}
UnchartedWorks
źródło
3

Odpowiedź @KiritModi w wersji Swift 4.2

func resizeImage(image: UIImage, targetSize: CGSize) -> UIImage {
    let size = image.size

    let widthRatio  = targetSize.width  / size.width
    let heightRatio = targetSize.height / size.height

    var newSize: CGSize
    if(widthRatio > heightRatio) {
        newSize = CGSize(width: size.width * heightRatio, height: size.height * heightRatio)
    } else {
        newSize = CGSize(width: size.width * widthRatio, height: size.height *      widthRatio)
    }

    let rect = CGRect(x: 0, y: 0, width: newSize.width, height: newSize.height)

    UIGraphicsBeginImageContextWithOptions(newSize, false, 1.0)
    image.draw(in: rect)
    let newImage = UIGraphicsGetImageFromCurrentImageContext()
    UIGraphicsEndImageContext()

    return newImage!
}
Ilya Stukalov
źródło
2

wywołanie metody resizeimage

let image1 = resizeimage(image: myimage.image!, withSize: CGSize(width:200, height: 200))

metoda zmiany rozmiaru obrazu

func resizeimage(image:UIImage,withSize:CGSize) -> UIImage {
        var actualHeight:CGFloat = image.size.height
        var actualWidth:CGFloat = image.size.width
        let maxHeight:CGFloat = withSize.height
        let maxWidth:CGFloat = withSize.width
        var imgRatio:CGFloat = actualWidth/actualHeight
        let maxRatio:CGFloat = maxWidth/maxHeight
        let compressionQuality = 0.5
        if (actualHeight>maxHeight||actualWidth>maxWidth) {
            if (imgRatio<maxRatio){
                //adjust width according to maxHeight
                imgRatio = maxHeight/actualHeight
                actualWidth = imgRatio * actualWidth
                actualHeight = maxHeight
            }else if(imgRatio>maxRatio){
                // adjust height according to maxWidth
                imgRatio = maxWidth/actualWidth
                actualHeight = imgRatio * actualHeight
                actualWidth = maxWidth
            }else{
                actualHeight = maxHeight
                actualWidth = maxWidth
            }
        }
        let rec:CGRect = CGRect(x:0.0,y:0.0,width:actualWidth,height:actualHeight)
        UIGraphicsBeginImageContext(rec.size)
        image.draw(in: rec)
        let image:UIImage = UIGraphicsGetImageFromCurrentImageContext()!
        let imageData = UIImageJPEGRepresentation(image, CGFloat(compressionQuality))
        UIGraphicsEndImageContext()
        let resizedimage = UIImage(data: imageData!)
        return resizedimage!
    }
Akbar Khan
źródło
2

Rozwiązanie Swift 4

Użyj tej funkcji

func image(with image: UIImage, scaledTo newSize: CGSize) -> UIImage {
    UIGraphicsBeginImageContextWithOptions(newSize, false, 1.0)
    image.draw(in: CGRect(x: 0, y: 0, width: newSize.width, height: newSize.height))
    let newImage = UIGraphicsGetImageFromCurrentImageContext()
    UIGraphicsEndImageContext()
    drawingImageView.image = newImage
    return newImage ?? UIImage()
}

Wywołanie funkcji: -

image(with: predictionImage, scaledTo: CGSize(width: 28.0, height: 28.0)

tutaj 28,0 to rozmiar piksela, który chcesz ustawić

PL DHIMAN
źródło
przypisanie powyżej zwrotu funkcji jest obce i powinno zostać usunięte:
BlueskyMed
2

Oto ogólna metoda (w języku Swift 5) zmniejszania obrazu w celu dopasowania go do rozmiaru. Wynikowy obraz może mieć ten sam współczynnik proporcji co oryginał lub może to być rozmiar docelowy z wyśrodkowanym obrazem oryginalnym. Jeśli obraz jest mniejszy niż rozmiar docelowy, nie jest zmieniany.

extension UIImage {
    func scaledDown(into size:CGSize, centered:Bool = false) -> UIImage {
        var (targetWidth, targetHeight) = (self.size.width, self.size.height)
        var (scaleW, scaleH) = (1 as CGFloat, 1 as CGFloat)
        if targetWidth > size.width {
            scaleW = size.width/targetWidth
        }
        if targetHeight > size.height {
            scaleH = size.height/targetHeight
        }
        let scale = min(scaleW,scaleH)
        targetWidth *= scale; targetHeight *= scale
        let sz = CGSize(width:targetWidth, height:targetHeight)
        if !centered {
            return UIGraphicsImageRenderer(size:sz).image { _ in
                self.draw(in:CGRect(origin:.zero, size:sz))
            }
        }
        let x = (size.width - targetWidth)/2
        let y = (size.height - targetHeight)/2
        let origin = CGPoint(x:x,y:y)
        return UIGraphicsImageRenderer(size:size).image { _ in
            self.draw(in:CGRect(origin:origin, size:sz))
        }
    }
}
matowe
źródło
2

Wydaje się, że wszystkie dotychczas wymienione odpowiedzi powodują zmniejszenie rozmiaru obrazu, jednak rozmiar nie jest mierzony w pikselach. Oto zmiana rozmiaru w oparciu o piksele Swift 5 .

extension UIImage {
    func resize(_ max_size: CGFloat) -> UIImage {
        // adjust for device pixel density
        let max_size_pixels = max_size / UIScreen.main.scale
        // work out aspect ratio
        let aspectRatio =  size.width/size.height
        // variables for storing calculated data
        var width: CGFloat
        var height: CGFloat
        var newImage: UIImage
        if aspectRatio > 1 {
            // landscape
            width = max_size_pixels
            height = max_size_pixels / aspectRatio
        } else {
            // portrait
            height = max_size_pixels
            width = max_size_pixels * aspectRatio
        }
        // create an image renderer of the correct size
        let renderer = UIGraphicsImageRenderer(size: CGSize(width: width, height: height), format: UIGraphicsImageRendererFormat.default())
        // render the image
        newImage = renderer.image {
            (context) in
            self.draw(in: CGRect(x: 0, y: 0, width: width, height: height))
        }
        // return the image
        return newImage
    }
} 

Stosowanie:

image.resize(500)
Ben
źródło
1

Przykład dotyczy minimalizacji obrazu do 1024 i mniej

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
    }

}
Urvish Modi
źródło
1

Możesz użyć tego do dopasowania obrazu w Swift 3 ;

extension UIImage {
    func resizedImage(newSize: CGSize) -> UIImage {
        // Guard newSize is different
        guard self.size != newSize else { return self }

        UIGraphicsBeginImageContextWithOptions(newSize, false, 0.0);
        self.draw(in: CGRect(x: 0, y: 0, width: newSize.width, height: newSize.height))
        let newImage: UIImage = UIGraphicsGetImageFromCurrentImageContext()!
        UIGraphicsEndImageContext()
        return newImage
    }

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

Stosowanie;

let resizedImage = image.resizedImageWithinRect(rectSize: CGSize(width: 1900, height: 1900))
Celil Bozkurt
źródło
1

Tutaj masz dwie proste funkcje UIImagerozszerzenia:

func scaledWithMaxWidthOrHeightValue(value: CGFloat) -> UIImage? {

    let width = self.size.width
    let height = self.size.height

    let ratio = width/height

    var newWidth = value
    var newHeight = value

    if ratio > 1 {
        newWidth = width * (newHeight/height)
    } else {
        newHeight = height * (newWidth/width)
    }

    UIGraphicsBeginImageContextWithOptions(CGSize(width: newWidth, height: newHeight), false, 0)

    draw(in: CGRect(x: 0, y: 0, width: newWidth, height: newHeight))

    let image = UIGraphicsGetImageFromCurrentImageContext()
    UIGraphicsEndImageContext()

    return image
}

func scaled(withScale scale: CGFloat) -> UIImage? {

    let size = CGSize(width: self.size.width * scale, height: self.size.height * scale)

    UIGraphicsBeginImageContextWithOptions(size, false, 0)

    draw(in: CGRect(x: 0, y: 0, width: size.width, height: size.height))

    let image = UIGraphicsGetImageFromCurrentImageContext()

    UIGraphicsEndImageContext()

    return image
}
Bartłomiej Semańczyk
źródło
Nie powinieneś wymuszać rozpakowywania opcjonalnego w zwrocie, ponieważ twoja deklaracja jest opcjonalna UIimage.
Andy Ibanez
1

Wrzucam tutaj moją wersję zaakceptowanej odpowiedzi, aby dobrze działała z Swift 5. To rozwiązanie nie wymusza rozpakowywania otrzymanego obrazu, co czyni go nieco bezpieczniejszym i ogólnie czystszym rozwiązaniem.

extension UIImage {
    public func resized(to target: CGSize) -> UIImage? {
        let ratio = min(
            target.height / size.height, target.width / size.width
        )
        let new = CGSize(
            width: size.width * ratio, height: size.height * ratio
        )
        UIGraphicsBeginImageContextWithOptions(new, false, 1.0)
        draw(in: CGRect(origin: .zero, size: new))
        defer { UIGraphicsEndImageContext() }
        return UIGraphicsGetImageFromCurrentImageContext()
    }
}
witek bobrowski
źródło
1

Rozszerzenie UIImage Swift 5

extension UIImage {
    func resize(_ width: CGFloat, _ height:CGFloat) -> UIImage? {
        let widthRatio  = width / size.width
        let heightRatio = height / size.height
        let ratio = widthRatio > heightRatio ? heightRatio : widthRatio
        let newSize = CGSize(width: size.width * ratio, height: size.height * ratio)
        let rect = CGRect(x: 0, y: 0, width: newSize.width, height: newSize.height)
        UIGraphicsBeginImageContextWithOptions(newSize, false, 1.0)
        self.draw(in: rect)
        let newImage = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        return newImage
    }
}


Użyj: UIImage (). Resize (200, 300)

Anand Khanpara
źródło
-1

SWIFT 5 z newImage = UIImage(cgImage: cgImage)

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)
                newImage = UIImage(cgImage: cgImage)
                UIGraphicsEndImageContext()

            }

            return newImage
   }
TD Nguyen
źródło