6

I want to use the function CGImageSourceCreateThumbnailAtIndex to create a thumbnail from an UIImage. All I have is the UIImage itself. The image is the snapshot on a UIView.

Please, I don't want to use any other method to create the thumbnail, just the one using CGImageSourceCreateThumbnailAtIndex, because I want to compare its performance with the other methods I already have.

Said that, this is the code I have so far.

I have create a UIImage category with this code:

- (UIImage *)createSquaredThumbnailWithWidth:(NSInteger)width {

  CFDictionaryRef options = (__bridge CFDictionaryRef) @{
                                                         (id) kCGImageSourceCreateThumbnailWithTransform : @YES,
                                                         (id) kCGImageSourceCreateThumbnailFromImageAlways : @YES,
                                                         (id) kCGImageSourceThumbnailMaxPixelSize : @(width)
                                                         };

  CGImageRef scaledImageRef = CGImageSourceCreateThumbnailAtIndex(????, 0, options);


  UIImage* scaled = [UIImage imageWithCGImage:scaledImageRef];

  CGImageRelease(scaledImageRef);

  return scaled;
}

My problem is with this line:

  CGImageRef scaledImageRef = CGImageSourceCreateThumbnailAtIndex(????, 0, options);

The first parameter of this function demands a CGImageSourceRef, but like I said, I just have an UIImage, that image is on memory, not on disk, and I don't want to save it to disk, or the performance will go down the drain.

How do I get a CGImageSourceRef from a UIImage that is on memory???

Duck
  • 34,902
  • 47
  • 248
  • 470

4 Answers4

23

Swift 4 code

let imageData = UIImagePNGRepresentation(image)!
let options = [
    kCGImageSourceCreateThumbnailWithTransform: true,
    kCGImageSourceCreateThumbnailFromImageAlways: true,
    kCGImageSourceThumbnailMaxPixelSize: 300] as CFDictionary
let source = CGImageSourceCreateWithData(imageData, nil)!
let imageReference = CGImageSourceCreateThumbnailAtIndex(source, 0, options)!
let thumbnail = UIImage(cgImage: imageReference)
Ivan Vavilov
  • 1,520
  • 1
  • 15
  • 28
  • This really came handy after series of web search! Thanks for this wonderful solution. – Aweda Mar 05 '18 at 10:19
  • 1
    Also review a post https://nshipster.com/image-resizing/ by mattt where he has listed many image scaling techniques and their performance benchmarks. – Vijayendra Jul 08 '20 at 14:03
  • How to make thumbnail image orientation not rotated, i tried by changing kCGImageSourceCreateThumbnailWithTransform to false, but still it is rotating, All i need is whether original image is of portrait or landscape , i dont need thumbnail to be rotated. – virtplay Aug 21 '20 at 14:43
  • @virtplay you can apply image rotation from original image: UIImage(cgImage: cgImage, scale: originalImage.scale, orientation: originalImage.imageOrientation) – snake302 Jul 10 '23 at 11:29
14

Swift 5.1 extension

based on Ivan's answer

extension UIImage {

  func getThumbnail() -> UIImage? {

    guard let imageData = self.pngData() else { return nil }

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

    guard let source = CGImageSourceCreateWithData(imageData as CFData, nil) else { return nil }
    guard let imageReference = CGImageSourceCreateThumbnailAtIndex(source, 0, options) else { return nil }

    return UIImage(cgImage: imageReference)

  }
}
Siempay
  • 876
  • 1
  • 11
  • 32
12

Have you try using CGImageSourceCreateWithData and passing image data as CFDataRef like this:

Note: Using CGImageSourceCreateWithData loses information about image rotation, use the CGImageSourceCreateWithURL for hassle free rotation of final image.

NSData *imageData = UIImagePNGRepresentation(image);
CGImageSourceRef src = CGImageSourceCreateWithData((__bridge CFDataRef)imageData, NULL);
CFDictionaryRef options = (__bridge CFDictionaryRef) @{
                                                     (id) kCGImageSourceCreateThumbnailWithTransform : @YES,
                                                     (id) kCGImageSourceCreateThumbnailFromImageAlways : @YES,
                                                     (id) kCGImageSourceThumbnailMaxPixelSize : @(width)
                                                     };

CGImageRef scaledImageRef = CGImageSourceCreateThumbnailAtIndex(src, 0, options);
CFRelease(src);
UIImage *scaled = [UIImage imageWithCGImage:scaledImageRef];
CGImageRelease(scaledImageRef);
return scaled;

Note: If you have URL of image then you can create CGImageSourceRef using CGImageSourceCreateWithURL.

CGImageSourceRef src = CGImageSourceCreateWithURL((__bridge CFURLRef)(imageFileURL), NULL);
Shebuka
  • 3,148
  • 1
  • 26
  • 43
Nirav D
  • 71,513
  • 12
  • 161
  • 183
0

Swift and iOS 15

func preparingThumbnail(of size: CGSize) -> UIImage?

Example would be:

let image = UIImage(named: "info")
image.preparingThumbnail(of size: CFSize(width: 300, height: 400))
Wladislaw
  • 1,200
  • 2
  • 12
  • 23