如何在 iOS 上调整位图大小

Posted

技术标签:

【中文标题】如何在 iOS 上调整位图大小【英文标题】:how to resize a bitmap on iOS 【发布时间】:2015-02-14 03:47:23 【问题描述】:

我想为我正在做的项目调整位图的大小。我设法通过将 cgbitmapcontextref 转换为像素数组,然后操纵像素数组,然后从操纵的像素数据生成新图像来做到这一点。这种方式极其繁琐。

我想知道是否有任何其他方法可以调整 CGBitmapContextRef 的大小。谢谢。

【问题讨论】:

【参考方案1】:

如果你不喜欢CGBitmapContextRef,这里有一些基于 UIKit 的简单图像大小调整例程。此扩展通过裁剪、缩放、方面填充和方面拟合(类似于 UIImageView 提供的一些主要内容模式)来调整图像大小。

//
//  UIImage+Resize.swift
//
//  Image resizing extension
//
//  Created by Robert Ryan on 19-May-11.
//  Ported to Swift by Robert Ryan on 12-Feb-15.
//  Modified for Swift 2 by Robert Ryan on 14-Oct-15
//  Modified for Swift 3 by Robert Ryan on 26-May-17
//  Modified for Swift 4 by Robert Ryan on 15-Feb-19
//
//  Inspired by http://ofcodeandmen.poltras.com/2008/10/30/undocumented-uiimage-resizing/
//  but adjusted to support AspectFill and AspectFit modes.
//
//  Copyright (c) 2015 Robert M. Ryan. All rights reserved.
//
//  This work by Robert M. Ryan is licensed under a Creative Commons Attribution-ShareAlike 4.0 International License.
//  http://creativecommons.org/licenses/by-sa/4.0/

import UIKit

extension UIImage 

    /// Resize the image to be the required size, stretching it as needed.
    ///
    /// - parameter newSize:      The new size of the image.
    /// - parameter contentMode:  The `UIView.ContentMode` to be applied when resizing image.
    ///                           Either `.scaleToFill`, `.scaleAspectFill`, or `.scaleAspectFit`.
    ///
    /// - returns:                Return `UIImage` of resized image.

    func scaled(to newSize: CGSize, contentMode: UIView.ContentMode = .scaleToFill) -> UIImage? 
        switch contentMode 
        case .scaleToFill:
            return filled(to: newSize)

        case .scaleAspectFill, .scaleAspectFit:
            let horizontalRatio = size.width  / newSize.width
            let verticalRatio   = size.height / newSize.height

            let ratio: CGFloat!
            if contentMode == .scaleAspectFill 
                ratio = min(horizontalRatio, verticalRatio)
             else 
                ratio = max(horizontalRatio, verticalRatio)
            

            let sizeForAspectScale = CGSize(width: size.width / ratio, height: size.height / ratio)
            let image = filled(to: sizeForAspectScale)
            let doesAspectFitNeedCropping = contentMode == .scaleAspectFit && (newSize.width > sizeForAspectScale.width || newSize.height > sizeForAspectScale.height)
            if contentMode == .scaleAspectFill || doesAspectFitNeedCropping 
                let subRect = CGRect(
                    x: floor((sizeForAspectScale.width - newSize.width) / 2.0),
                    y: floor((sizeForAspectScale.height - newSize.height) / 2.0),
                    width: newSize.width,
                    height: newSize.height)
                return image?.cropped(to: subRect)
            
            return image

        default:
            return nil
        
    

    /// Resize the image to be the required size, stretching it as needed.
    ///
    /// - parameter newSize:   The new size of the image.
    ///
    /// - returns:             Resized `UIImage` of resized image.

    func filled(to newSize: CGSize) -> UIImage? 
        let format = UIGraphicsImageRendererFormat()
        format.opaque = false
        format.scale = scale

        return UIGraphicsImageRenderer(size: newSize, format: format).image  _ in
            draw(in: CGRect(origin: .zero, size: newSize))
        
    

    /// Crop the image to be the required size.
    ///
    /// - parameter bounds:    The bounds to which the new image should be cropped.
    ///
    /// - returns:             Cropped `UIImage`.

    func cropped(to bounds: CGRect) -> UIImage? 
        // if bounds is entirely within image, do simple CGImage `cropping` ...

        if CGRect(origin: .zero, size: size).contains(bounds), imageOrientation == .up, let cgImage = cgImage 
            return cgImage.cropping(to: bounds * scale).flatMap 
                UIImage(cgImage: $0, scale: scale, orientation: imageOrientation)
            
        

        // ... otherwise, manually render whole image, only drawing what we need

        let format = UIGraphicsImageRendererFormat()
        format.opaque = false
        format.scale = scale

        return UIGraphicsImageRenderer(size: bounds.size, format: format).image  _ in
            let origin = CGPoint(x: -bounds.minX, y: -bounds.minY)
            draw(in: CGRect(origin: origin, size: size))
        
    

    /// Resize the image to fill the rectange of the specified size, preserving the aspect ratio, trimming if needed.
    ///
    /// - parameter newSize:   The new size of the image.
    ///
    /// - returns:             Return `UIImage` of resized image.

    func scaledAspectFill(to newSize: CGSize) -> UIImage? 
        return scaled(to: newSize, contentMode: .scaleAspectFill)
    

    /// Resize the image to fit within the required size, preserving the aspect ratio, with no trimming taking place.
    ///
    /// - parameter newSize:   The new size of the image.
    ///
    /// - returns:             Return `UIImage` of resized image.

    func scaledAspectFit(to newSize: CGSize) -> UIImage? 
        return scaled(to: newSize, contentMode: .scaleAspectFit)
    



extension CGSize 
    static func * (lhs: CGSize, rhs: CGFloat) -> CGSize 
        return CGSize(width: lhs.width * rhs, height: lhs.height * rhs)
    


extension CGPoint 
    static func * (lhs: CGPoint, rhs: CGFloat) -> CGPoint 
        return CGPoint(x: lhs.x * rhs, y: lhs.y * rhs)
    


extension CGRect 
    static func * (lhs: CGRect, rhs: CGFloat) -> CGRect 
        return CGRect(origin: lhs.origin * rhs, size: lhs.size * rhs)
    

对于 Swift 2 版本,请参阅此答案的先前版本。

【讨论】:

不幸的是,我嫁给了 cgbitmapcontext。谢谢。很确定你的权利,但没有一个简单的方法可以做到这一点。

以上是关于如何在 iOS 上调整位图大小的主要内容,如果未能解决你的问题,请参考以下文章

我如何正确调整位图的大小?

在android上调整位图大小的最节省内存的方法?

如何在 iOS 设备上调整图像大小?

如何在iOS中phonegap插件的点击事件上调整cordova Webview的大小

如何在上传到服务器之前在 iOS 上压缩/调整图像大小?

Android:如何将整个 ImageView 转换为位图?