如何在Swift中获取图像文件大小?

52

我正在使用

UIImagePickerControllerDelegate,
UINavigationControllerDelegate,
UIPopoverControllerDelegate

这些代表可以从我的相册或者摄像头中选择图像。那么,在选择图像后,我如何获得图像文件的大小?

我想使用以下代码:

let filePath = "your path here"
    var fileSize : UInt64 = 0

    do {
        let attr : NSDictionary? = try NSFileManager.defaultManager().attributesOfItemAtPath(filePath)

        if let _attr = attr {
            fileSize = _attr.fileSize();
            print(fileSize)
        }
    } catch {
    }

但是在这里我需要一个路径,但是如果没有路径,仅凭图像文件怎么办?


请查看这个答案 - TheTiger
14个回答

100

请查看谷歌搜索“1KB等于多少字节”,答案为1000。

https://www.google.com/search?q=1+kb+%3D+how+many+bytes&oq=1+kb+%3D+how+many+bytes&aqs=chrome..69i57.8999j0j1&sourceid=chrome&ie=UTF-8


在获取适当的大小时,我通过将图像添加到应用程序包和模拟器中的照片中添加了多个方案。 我从我的 Mac 上取出的图像大小为299.0 KB。


场景1:将图像添加到应用程序包中

在 Xcode 中添加图像后,它在项目目录中的大小将保持不变。但是,如果您从其路径获取它,则其大小将缩小到257.0 KB。这是设备或模拟器中使用的图像的实际大小。

    guard let aStrUrl = Bundle.main.path(forResource: "1", ofType: "png") else { return }

   let aUrl = URL(fileURLWithPath: aStrUrl)
   print("Img size = \((Double(aUrl.fileSize) / 1000.00).rounded()) KB")

   extension URL {
        var attributes: [FileAttributeKey : Any]? {
            do {
                return try FileManager.default.attributesOfItem(atPath: path)
            } catch let error as NSError {
                print("FileAttribute error: \(error)")
            }
            return nil
        }

        var fileSize: UInt64 {
            return attributes?[.size] as? UInt64 ?? UInt64(0)
        }

        var fileSizeString: String {
            return ByteCountFormatter.string(fromByteCount: Int64(fileSize), countStyle: .file)
        }

        var creationDate: Date? {
            return attributes?[.creationDate] as? Date
        }
    }

方案2: 在模拟器中向照片添加图像

将图像添加到模拟器或设备的照片中,图像的大小从299.0 KB增加到393.0 KB。这是存储在设备或模拟器文档目录中的图像的实际大小。

Swift 4及更早版本

var image = info[UIImagePickerControllerOriginalImage] as! UIImage
var imgData: NSData = NSData(data: UIImageJPEGRepresentation((image), 1)) 
// var imgData: NSData = UIImagePNGRepresentation(image) 
// you can also replace UIImageJPEGRepresentation with UIImagePNGRepresentation.
var imageSize: Int = imgData.count
print("size of image in KB: %f ", Double(imageSize) / 1000.0)

Swift 5

let image = info[UIImagePickerController.InfoKey.originalImage] as! UIImage

let imgData = NSData(data: image.jpegData(compressionQuality: 1)!)
var imageSize: Int = imgData.count
print("actual size of image in KB: %f ", Double(imageSize) / 1000.0)   

通过添加 .rounded(),它会给你 393.0 KB,不使用它将给出 393.442 KB。因此,请使用上述代码手动检查图像大小一次。由于图像的大小可能因不同的设备和 Mac 而异。我只在 Mac mini 和模拟器 iPhone XS 上进行了检查。


2
你认为在图像压缩后(UIImageJPEGRepresentation((image), 0.5))你会得到正确的大小吗? - Adarsh G J
它将提供您图像的当前大小。但是,如果您将压缩设置为1,则会提供原始图像未经压缩的大小。 - Dhaivat Vyas
@DhaivatVyas 压缩方面怎么样?会使我的图像质量变差还是正常的?我现在正在寻找压缩方法,如果这种方法可以,那么我会使用它。 - Orkhan Alizade
2
通过压缩,使用UIImageJPEGRepresentation会影响图像的质量。但是如果你使用UIImagePNGRepresentation,它将占用更多的空间。通过降低图像质量,会丢失一些数据并且质量会受到影响。如果你使用JPEGRepresentation,请尽量不要低于0.7,在某些情况下不要低于0.5。因为质量会受到更大的影响。但是根据你应用中对图像的需求,你需要通过试错的方式进行检查。 - Dhaivat Vyas
1
您还可以根据所需的文件大小缩小图像质量。例如,如果当前图像大小为10 MB,而您只需要最大1 MB的图像大小,则也可以完成此操作。请访问以下网址以获取帮助: "https://dev59.com/knRB5IYBdhLWcg3weHLx#613380" 和 "https://dev59.com/CF4b5IYBdhLWcg3wchNL#29137723"。同时,您还可以在以下网址将obj-C代码转换为swift: "https://objectivec2swift.com/#/converter/code"。 - Dhaivat Vyas
显示剩余3条评论

19
extension UIImage {

    public enum DataUnits: String {
        case byte, kilobyte, megabyte, gigabyte
    }

    func getSizeIn(_ type: DataUnits)-> String {

        guard let data = self.pngData() else {
            return ""
        }

        var size: Double = 0.0

        switch type {
        case .byte:
            size = Double(data.count)
        case .kilobyte:
            size = Double(data.count) / 1024
        case .megabyte:
            size = Double(data.count) / 1024 / 1024
        case .gigabyte:
            size = Double(data.count) / 1024 / 1024 / 1024
        }

        return String(format: "%.2f", size)
    }
}

用法示例:print("图片大小为 \(yourImage.getSizeIn(.megabyte)) mb")


它给出的尺寸与原始尺寸不同。 - aqsa arshad
@aqsaarshad 我认为这是由于数据转换引起的,此代码将任何类型的UIImage转换为PNG数据以获取大小,当您的图像为JPEG时,可能会导致数据大小发生变化??我不确定。 - Coder ACJHP
千(kilo)表示10的3次方,兆(mega)表示10的6次方。因此,你需要除以1000。 - zsyesenko

12

Swift 3/4:

if let imageData = UIImagePNGRepresentation(image) {
     let bytes = imageData.count
     let kB = Double(bytes) / 1000.0 // Note the difference
     let KB = Double(bytes) / 1024.0 // Note the difference
}
请注意 kB 和 KB 之间的区别。我在这里回答是因为我们在考虑一个千字节等于 1024 字节的问题时,我的情况和服务器端认为它等于 1000 字节,这导致了问题。点击链接了解更多信息。链接
PS:几乎肯定您会选择 kB(1000)。

4

详情

  • Xcode 10.2.1(10E1001),Swift 5

解决方案

extension String {
    func getNumbers() -> [NSNumber] {
        let formatter = NumberFormatter()
        formatter.numberStyle = .decimal
        let charset = CharacterSet.init(charactersIn: " ,.")
        return matches(for: "[+-]?([0-9]+([., ][0-9]*)*|[.][0-9]+)").compactMap { string in
            return formatter.number(from: string.trimmingCharacters(in: charset))
        }
    }

    // https://dev59.com/aF4c5IYBdhLWcg3weaT8#54900097
    func matches(for regex: String) -> [String] {
        guard let regex = try? NSRegularExpression(pattern: regex, options: [.caseInsensitive]) else { return [] }
        let matches  = regex.matches(in: self, options: [], range: NSMakeRange(0, self.count))
        return matches.compactMap { match in
            guard let range = Range(match.range, in: self) else { return nil }
            return String(self[range])
        }
    }
}

extension UIImage {
    func getFileSizeInfo(allowedUnits: ByteCountFormatter.Units = .useMB,
                         countStyle: ByteCountFormatter.CountStyle = .file) -> String? {
        // https://developer.apple.com/documentation/foundation/bytecountformatter
        let formatter = ByteCountFormatter()
        formatter.allowedUnits = allowedUnits
        formatter.countStyle = countStyle
        return getSizeInfo(formatter: formatter)
    }

    func getFileSize(allowedUnits: ByteCountFormatter.Units = .useMB,
                     countStyle: ByteCountFormatter.CountStyle = .memory) -> Double? {
        guard let num = getFileSizeInfo(allowedUnits: allowedUnits, countStyle: countStyle)?.getNumbers().first else { return nil }
        return Double(truncating: num)
    }

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

用法

guard let image = UIImage(named: "img") else { return }
if let imageSizeInfo = image.getFileSizeInfo() {
    print("\(imageSizeInfo), \(type(of: imageSizeInfo))") // 51.9 MB, String
}

if let imageSizeInfo = image.getFileSizeInfo(allowedUnits: .useBytes, countStyle: .file) {
    print("\(imageSizeInfo), \(type(of: imageSizeInfo))") // 54,411,697 bytes, String
}

if let imageSizeInfo = image.getFileSizeInfo(allowedUnits: .useKB, countStyle: .decimal) {
    print("\(imageSizeInfo), \(type(of: imageSizeInfo))") // 54,412 KB, String
}

if let size = image.getFileSize() {
    print("\(size), \(type(of: size))") // 51.9, Double
}

2

尝试使用以下方法从URL获取大小:

func fileSize(url: URL) -> String? {
        
        var fileSize:Int?
        do {
            let resources = try url.resourceValues(forKeys:[.fileSizeKey])
            fileSize = resources.fileSize!
            print ("\(String(describing: fileSize))")
        } catch {
            print("Error: \(error)")
        }
        
        // bytes
        if fileSize! < 999 {
            return String(format: "%lu bytes", CUnsignedLong(bitPattern: fileSize!))
        }
        // KB
        var floatSize = Float(fileSize! / 1000)
        if floatSize < 999 {
            return String(format: "%.1f KB", floatSize)
        }
        // MB
        floatSize = floatSize / 1000
        if floatSize < 999 {
            return String(format: "%.1f MB", floatSize)
        }
        // GB
        floatSize = floatSize / 1000
        return String(format: "%.1f GB", floatSize)
    }

使用示例

let sizeInString = fileSize(url: url)  
print("FileSize = "+sizeInString!)

2

Swift 3

let uploadData = UIImagePNGRepresentation(image)
let array = [UInt8](uploadData)
print("Image size in bytes:\(array.count)")

上传数据的数量和数组的数量有什么区别? 我需要将其转换为[UInt8]吗? - magpoc
没有得到实际大小。 - Arshad Shaik
Uint8会限制任何大文件。 - Juan Boero

1
let selectedImage = info[UIImagePickerControllerOriginalImage] as!  UIImage 
let selectedImageData: NSData = NSData(data:UIImageJPEGRepresentation((selectedImage), 1)) 
let selectedImageSize:Int = selectedImageData.length 
print("Image Size: %f KB", selectedImageSize /1024.0)

1

1

Swift 4.2

let jpegData = image.jpegData(compressionQuality: 1.0)
let jpegSize: Int = jpegData?.count ?? 0
print("size of jpeg image in KB: %f ", Double(jpegSize) / 1024.0)

1
let imageData = UIImageJPEGRepresentation(image, 1)
let imageSize = imageData?.count

UIImageJPEGRepresentation - 返回指定图像的数据对象,格式为JPEG。值1.0表示最小压缩程度(接近原始图像)

imageData?.count - 返回数据长度(字符数等于字节数)

重要提示! UIImageJPEGRepresentationUIImagePNGRepresentation不会返回原始图像。但是,如果将给定的数据用作上传的源,则文件大小将与服务器上的文件大小相同(即使使用压缩也是如此)。


6
你可能需要在回答中提供一些背景信息。 - Matthieu Brucher

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接