3

I would like to take a UIImage and output a 100 by 100 version of it to use as a thumbnail. I found some answers on SO for how to do this in objective-C but not swift and wasn't sure where to start. I also found the link (https://nshipster.com/image-resizing/#technique-3-creating-a-thumbnail-with-image-io) which suggests it isn't as straight forward as I would have hoped. That link had me hopeful that one of the approaches may work, but each references a URL argument which confused me since I am starting with a UIImage as the input.

In a a similar situation (user uploading a picture from phone) I use the code below to create a thumbnail from the asset, I am looking for help doing the same thing when the input is a UIImage instead of a PHAsset.

func getAssetThumbnail(asset: PHAsset) -> UIImage {
        let manager = PHImageManager.default()
        let option = PHImageRequestOptions()
        var thumbnail = UIImage()
        option.isSynchronous = true

        manager.requestImage(for: asset, targetSize: CGSize(width: 100, height: 100), contentMode: .aspectFit, options: option, resultHandler: {(result, info)->Void in
            thumbnail = result!
        })
        return thumbnail
    }
Daniel Patriarca
  • 361
  • 3
  • 20

3 Answers3

5

iOS 15 added the following beta APIs to UIImage.

func prepareThumbnail(of: CGSize, completionHandler: (UIImage?) -> Void)
func preparingThumbnail(of: CGSize) -> UIImage?

https://developer.apple.com/documentation/uikit/uiimage/

Kousuke Ariga
  • 691
  • 9
  • 10
3

Tested the code, and this works fine for me:- (Swift 5.0)

let yourImage = UIImage()

if let imageData = yourImage.pngData(){
    let options = [
        kCGImageSourceCreateThumbnailWithTransform: true,
        kCGImageSourceCreateThumbnailFromImageAlways: true,
        kCGImageSourceThumbnailMaxPixelSize: 100] as CFDictionary // Specify your desired size at kCGImageSourceThumbnailMaxPixelSize. I've specified 100 as per your question

    imageData.withUnsafeBytes { ptr in
       guard let bytes = ptr.baseAddress?.assumingMemoryBound(to: UInt8.self) else {
          return
       }
       if let cfData = CFDataCreate(kCFAllocatorDefault, bytes, imageData.count){
          let source = CGImageSourceCreateWithData(cfData, nil)!
          let imageReference = CGImageSourceCreateThumbnailAtIndex(source, 0, options)!
          let thumbnail = UIImage(cgImage: imageReference) // You get your thumbail here
       }
    }
}
Lokesh SN
  • 1,583
  • 7
  • 23
1

For future reference, I've just come across the same issue and this thread has some nice solutions: Creating a thumbnail from UIImage using CGImageSourceCreateThumbnailAtIndex

I went with this, which is working nicely in Swift 5.3:

let uiImage = someUIImage

let options = [
    kCGImageSourceCreateThumbnailWithTransform: true,
    kCGImageSourceCreateThumbnailFromImageAlways: true,
    kCGImageSourceThumbnailMaxPixelSize: 100] as CFDictionary

guard let imageData = uiImage.pngData(),
      let imageSource = CGImageSourceCreateWithData(imageData as NSData, nil),
      let image = CGImageSourceCreateThumbnailAtIndex(imageSource, 0, options)
else {
    return nil
}

return UIImage(cgImage: image)
ADB
  • 591
  • 7
  • 21