How to get image file size in Swift?
Asked Answered
R

14

52

I am using

UIImagePickerControllerDelegate,
UINavigationControllerDelegate,
UIPopoverControllerDelegate

these delegates for choosing image from my gallery or my camera. So, how can I get image file size after choosing an image?

I want to use this:

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

but here I need a path, but how can I get without a path, just by image file?

Raddle answered 14/12, 2015 at 8:49 Comment(2)
Possible duplicate of Get size of a UIImage (bytes length) not height and widthAutoxidation
Please see this answerVulnerary
I
100

Please check the google for 1 kb to bytes it will be 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


So while getting the proper size I’ve added multiple scenario by adding image in App Bundle and in photos in simulator. Well the image which I took from my Mac was of 299.0 KB.


Scenario 1: Adding image to Application Bundle

On adding image in your Xcode the size of the image will remain same in project directory. But you get it from its path the size will be reduced to 257.0 KB. Which is the actual size of the image used in the device or simulator.

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

Scenario 2: Adding image to Photos in Simulator

On adding image to photos in simulator or device the size of the image increased from 299.0 KB to 393.0 KB. Which is the actual size of the image stored in the device or simulator’s document directory.

Swift 4 and earlier

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)   

By adding .rounded() it will give you 393.0 KB and without using it it will give 393.442 KB. So please check the image size manually once using the above code. As the size of image may vary in different devices and mac. I've check it only on mac mini and simulator iPhone XS.

Irriguous answered 14/12, 2015 at 9:5 Comment(8)
Did you think after the image compress (UIImageJPEGRepresentation((image), 0.5)) u will get the correct size ?Sumer
It will give you the current size of your image. But you can also set compression to 1 then it will give you size of your original image without compression.Irriguous
@DhaivatVyas what about the compression? Will it make my image quality worst or it's normal? I'm now searching compressing method for it and if this method is OK, then I would you itRaddle
By doing compression it will affect the quality of image in you are using UIImageJPEGRepresentation. But if you if you are using UIImagePNGRepresentation it will occupy more space. As by reducing the quality in image will lose some data and it's quality will be affected. If you are using JPEGRepresentation try not to go below 0.7 and in some case not to go below 0.5. As the quality will be more affected. But again you need to check by trial and error basis, based on your requirement of image in your application.Irriguous
You can also reduce quality of image based on the file size you require. EX: If your current image size in 10 MB and you require only 1 MB of max image size then it can also be done. visit this urls : "https://mcmap.net/q/146259/-how-to-easily-resize-optimize-an-image-size-with-ios" and "https://mcmap.net/q/146260/-how-do-i-resize-the-uiimage-to-reduce-upload-image-size". This will also help. Also you can convert obj-C code to swift in this url : "objectivec2swift.com/#/converter/code".Irriguous
In swift 3.0, you will have to change the last line of code to: print("size of image in KB: %f ", Double(imageSize) / 1024.0) Xcode throws an error that says you can use the '/' operator on incompatible operands.Shawana
@DhaivatVyas But the actual size and the size that we got from the above code are different. My image file size is 691 Kb when i checked from my laptop finder by going to "Get Info", but from the above code it displays "size of image in KB: %f 403.34375" . Please correct me if i am wrong.Riocard
@ArshadShaik Please check the updated answer and also check both of the scenario.Irriguous
W
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)
    }
}

Usage example : print("Image size \(yourImage.getSizeIn(.megabyte)) mb")

Waldenses answered 29/4, 2020 at 15:45 Comment(3)
It gives different size than original size.Turne
@aqsaarshad I think it's because of data conversion, this code convert any type of UIImage to PNG data to get size and when your image is JPEG there may data size changes?? I am not sure.Waldenses
kilo means 10^3, mega 10^6. So you need to divide by 1000.Ingemar
P
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
}

Please note the difference between kB and KB. Answering here because in my case we had an issue while we considered kilobyte as 1024 bytes but server side considered it as 1000 bytes which caused an issue. Link to learn more.

PS. Almost sure you'll go with kB (1000).

Porism answered 15/11, 2017 at 21:9 Comment(0)
B
4

Details

  • Xcode 10.2.1 (10E1001), Swift 5

Solution

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://mcmap.net/q/23817/-swift-extract-regex-matches
    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))
    }
}

Usage

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
}
Brooks answered 19/4, 2019 at 17:15 Comment(0)
S
2

Swift 3

let uploadData = UIImagePNGRepresentation(image)
let array = [UInt8](uploadData)
print("Image size in bytes:\(array.count)")
Sink answered 15/3, 2017 at 14:33 Comment(3)
What's the difference between uploadData.count and array.count? Do I need to cast to [UInt8]?Leveller
Didn't get actual size.Riocard
Uint8 will limit any big fileMontgomery
P
2

try this for getting size from 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)
    }

Use Example

let sizeInString = fileSize(url: url)  
print("FileSize = "+sizeInString!)
Periodate answered 11/1, 2022 at 5:52 Comment(0)
S
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)
Sumer answered 14/12, 2015 at 9:24 Comment(0)
B
1
let data = UIImageJPEGRepresentation(image, 1)
let imageSize = data?.count

Duplicate of How to get the size of a UIImage in KB?

Bartel answered 14/12, 2015 at 9:36 Comment(0)
W
1
let imageData = UIImageJPEGRepresentation(image, 1)
let imageSize = imageData?.count

UIImageJPEGRepresentation — returns the Data object for the specified image in JPEG format. The value 1.0 represents the least compression (close to original image).

imageData?.count — return data length (chars count equals bytes).

Important! UIImageJPEGRepresentation or UIImagePNGRepresentation will not return the original image. But if use given Data as source for uploading - than file size be the same as on the server (even using compression).

Watertight answered 21/1, 2019 at 10:43 Comment(1)
You may want to provide some context to your answer.Goldy
C
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)
Cask answered 28/2, 2019 at 5:10 Comment(0)
I
0

Try this code (Swift 4.2)

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

And use example

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

        let aUrl = URL(fileURLWithPath: aStrUrl)

        print("Img size = \((Double(aUrl.fileSize) / 1000.00).rounded()) KB")
Intermediate answered 22/4, 2019 at 9:9 Comment(0)
P
0

//Swift 4

if let pickedImage = info[UIImagePickerControllerOriginalImage] as? UIImage {
        ///check image Size
       let imgData = NSData(data: UIImageJPEGRepresentation((pickedImage), 1)!)
       let imageSize: Int = imgData.count
       print("size of image in KB: %f ", Double(imageSize) / 1024.0)
       print("size of image in MB: %f ", Double(imageSize) / 1024.0 / 1024)    

    }
Punctuate answered 7/5, 2019 at 7:6 Comment(0)
D
0

I make work around data units conversion :

Bytes -> KB -> MB -> GB -> ... -> Extremest Monster Data

enum dataUnits:CaseIterable {
case B      //Byte
case KB     //kilobyte
case MB     //megabyte
case GB     //gigabyte
case TB     //terabyte
case PB     //petabyte
case EB     //exabyte
case ZB     //zettabyte
case YB     //yottabyte
case BD     //Big Data
case BBx    // Extra Big Bytes
case BBxx   // 2 time Extra Big Bytes
case BBxxx  // 3 time Extra Big Bytes
case BBxxxx // 4 time Extra Big Bytes
case MBB    // Monster Big Bytes 
}
func convertStorageUnit(data n:Double,inputDataUnit unitLevel:Int,roundPoint:Int = 2,nG:Double = 1000.0)->String{
if(n>=nG){
    return convertStorageUnit(data:n/1024,inputDataUnit:unitLevel+1) 
}else{
    let ut = unitLevel > dataUnits.allCases.count + 1 ? "Extreme Monster Data" : dataUnits.allCases.map{"\($0)"}[unitLevel]

   return "\(String(format:"%.\(roundPoint)f",n)) \(ut)"
}

}

print(
convertStorageUnit(data:99922323343439789798789898989897987945454545920,
inputDataUnit:dataUnits.allCases.firstIndex(of: .B)!,roundPoint: 0)
)

output : 8.87 PB

Note: Input data length should be less than 64-bit OR Change data type According

Deina answered 18/12, 2019 at 6:18 Comment(0)
R
-3

Try this

import Darwin

...    

let size = malloc_size(&_attr)
Roundhouse answered 14/12, 2015 at 9:3 Comment(1)
what is &_attr?Catarina

© 2022 - 2024 — McMap. All rights reserved.