skip to Main Content

I have an app that can choose photo from gallery and then upload it to the server.

I have 2 requirements from the server side:

  1. Compress image to 1mb max
  2. Image should have metada/exif data

To select image from gallery, I’m using new SwiftUI .photosPicker

Then I use .loadTransferable that returns me image Data.

photo.loadTransferable(type: Data.self) { result in }

When I load this Data to the server, EXIF/metadata is there. And that’s great. But I need to compress image data.
I found a way to compress image data like this:

UIImage(data: data)?.jpegData(compressionQuality: 1)

And the problem is that after this compression, EXIF/metadata is LOST. UIImage cut it.

Question:

How to compress image Data without wrapping it to UIImage?

Or is there another way to compress image data and do not lose EXIF/metadata?

2

Answers


  1. You’re right, converting the image data to a UIImage and then compressing it with jpegData removes the EXIF data. Here’s how you can achieve both compression and preserve EXIF data:

    This approach uses CGImageSource and CGImageDestination to create a compressed version of the image while keeping the EXIF data intact.

    func compressImage(data: Data, targetSize: Int = 1024 * 1024) throws -> Data {
      guard let source = CGImageSourceCreateWithData(data as CFData, nil) else {
        throw NSError(domain: "com.yourapp.error", code: 1, userInfo: ["message": "Failed to create image source"])
      }
    
      let options: CFDictionary = [
        kCGImageDestinationLosslessDecodeForEditing: kCFBooleanTrue,
        kCGImageDestinationAllowPartialDecoding: kCFBooleanTrue,
        kCGImagePropertyMagicNumber: kCFDataRef(data),
      ]
    
      let compressedData = NSMutableData()
      guard let destination = CGImageDestinationCreateWithData(compressedData as CFMutableData, kUTTypeJPEG, 1, options) else {
        throw NSError(domain: "com.yourapp.error", code: 1, userInfo: ["message": "Failed to create image destination"])
      }
    
      // Set compression quality (adjust as needed)
      let quality = 0.8
    
      let properties = [kCGImageDestinationJPEGQuality: quality]
      CGImageDestinationAddImageFromSource(destination, source, 0, properties)
    
      if !CGImageDestinationFinalize(destination) {
        throw NSError(domain: "com.yourapp.error", code: 1, userInfo: ["message": "Failed to finalize image destination"])
      }
    
      return compressedData as Data
    }
    

    However, there are several libraries like SDWebImage or SwiftyJPEG offer functionalities for compressing images while preserving metadata. These libraries might provide a more concise solution but come with the overhead of managing external dependencies

    Login or Signup to reply.
  2. I’m having the same problem. I still want to retain the size value and image quality But to reduce the image size. .jpegData() or pngData() produces a capacity greater than 92% of the original image – This is unreasonable.
    Is there any approach in Swift? I think VSCO is doing that very well

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search