title: Scaling Images: how can the accelerate be the slowest method?
body: <p>I am testing several methods to rescale a UIImage. </p>
  
  <p>I have tested all these methods posted <a href="http://nshipster.com/image-resizing/" rel="nofollow">here</a> and measured the time they take to resize an image.</p>
  
  <p><strong>1) UIGraphicsBeginImageContextWithOptions &amp; UIImage -drawInRect:</strong></p>
  
  <pre><code>let image = UIImage(contentsOfFile: self.URL.path!)
  
  let size = CGSizeApplyAffineTransform(image.size, CGAffineTransformMakeScale(0.5, 0.5))
  let hasAlpha = false
  let scale: CGFloat = 0.0 // Automatically use scale factor of main screen
  
  UIGraphicsBeginImageContextWithOptions(size, !hasAlpha, scale)
  image.drawInRect(CGRect(origin: CGPointZero, size: size))
  
  let scaledImage = UIGraphicsGetImageFromCurrentImageContext()
  UIGraphicsEndImageContext()
  </code></pre>
  
  <p><strong>2) CGBitmapContextCreate &amp; CGContextDrawImage</strong></p>
  
  <pre><code>let cgImage = UIImage(contentsOfFile: self.URL.path!).CGImage
  
  let width = CGImageGetWidth(cgImage) / 2
  let height = CGImageGetHeight(cgImage) / 2
  let bitsPerComponent = CGImageGetBitsPerComponent(cgImage)
  let bytesPerRow = CGImageGetBytesPerRow(cgImage)
  let colorSpace = CGImageGetColorSpace(cgImage)
  let bitmapInfo = CGImageGetBitmapInfo(cgImage)
  
  let context = CGBitmapContextCreate(nil, width, height, bitsPerComponent, bytesPerRow, colorSpace, bitmapInfo.rawValue)
  
  CGContextSetInterpolationQuality(context, kCGInterpolationHigh)
  
  CGContextDrawImage(context, CGRect(origin: CGPointZero, size: CGSize(width: CGFloat(width), height: CGFloat(height))), cgImage)
  
  let scaledImage = CGBitmapContextCreateImage(context).flatMap { UIImage(CGImage: $0) }
  </code></pre>
  
  <p><strong>3) CGImageSourceCreateThumbnailAtIndex</strong></p>
  
  <pre><code>import ImageIO
  
  if let imageSource = CGImageSourceCreateWithURL(self.URL, nil) {
      let options: [NSString: NSObject] = [
          kCGImageSourceThumbnailMaxPixelSize: max(size.width, size.height) / 2.0,
          kCGImageSourceCreateThumbnailFromImageAlways: true
      ]
  
      let scaledImage = CGImageSourceCreateThumbnailAtIndex(imageSource, 0, options).flatMap { UIImage(CGImage: $0) }
  }
  </code></pre>
  
  <p><strong>4) Lanczos Resampling with Core Image</strong></p>
  
  <pre><code>let image = CIImage(contentsOfURL: self.URL)
  
  let filter = CIFilter(name: "CILanczosScaleTransform")!
  filter.setValue(image, forKey: "inputImage")
  filter.setValue(0.5, forKey: "inputScale")
  filter.setValue(1.0, forKey: "inputAspectRatio")
  let outputImage = filter.valueForKey("outputImage") as! CIImage
  
  let context = CIContext(options: [kCIContextUseSoftwareRenderer: false])
  let scaledImage = UIImage(CGImage: self.context.createCGImage(outputImage, fromRect: outputImage.extent()))
  </code></pre>
  
  <p><strong>5) vImage in Accelerate</strong></p>
  
  <pre><code>let cgImage = UIImage(contentsOfFile: self.URL.path!).CGImage
  
  // create a source buffer
  var format = vImage_CGImageFormat(bitsPerComponent: 8, bitsPerPixel: 32, colorSpace: nil, 
      bitmapInfo: CGBitmapInfo(rawValue: CGImageAlphaInfo.First.rawValue), 
      version: 0, decode: nil, renderingIntent: CGColorRenderingIntent.RenderingIntentDefault)
  var sourceBuffer = vImage_Buffer()
  defer {
      sourceBuffer.data.dealloc(Int(sourceBuffer.height) * Int(sourceBuffer.height) * 4)
  }
  
  var error = vImageBuffer_InitWithCGImage(&amp;sourceBuffer, &amp;format, nil, cgImage, numericCast(kvImageNoFlags))
  guard error == kvImageNoError else { return nil }
  
  // create a destination buffer
  let scale = UIScreen.mainScreen().scale
  let destWidth = Int(image.size.width * 0.5 * scale)
  let destHeight = Int(image.size.height * 0.5 * scale)
  let bytesPerPixel = CGImageGetBitsPerPixel(image.CGImage) / 8
  let destBytesPerRow = destWidth * bytesPerPixel
  let destData = UnsafeMutablePointer&lt;UInt8&gt;.alloc(destHeight * destBytesPerRow)
  defer {
      destData.dealloc(destHeight * destBytesPerRow)
  }
  var destBuffer = vImage_Buffer(data: destData, height: vImagePixelCount(destHeight), width: vImagePixelCount(destWidth), rowBytes: destBytesPerRow)
  
  // scale the image
  error = vImageScale_ARGB8888(&amp;sourceBuffer, &amp;destBuffer, nil, numericCast(kvImageHighQualityResampling))
  guard error == kvImageNoError else { return nil }
  
  // create a CGImage from vImage_Buffer
  let destCGImage = vImageCreateCGImageFromBuffer(&amp;destBuffer, &amp;format, nil, nil, numericCast(kvImageNoFlags), &amp;error)?.takeRetainedValue()
  guard error == kvImageNoError else { return nil }
  
  // create a UIImage
  let scaledImage = destCGImage.flatMap { UIImage(CGImage: $0, scale: 0.0, orientation: image.imageOrientation) }
  </code></pre>
  
  <p>After testing this for hours and measure the time every method took for rescaling the images to 100x100, my conclusions are completely different from NSHipster. First of all the <code>vImage in accelerate</code> is 200 times slower than the first method, that in my opinion is the poor cousin of the other ones. The core image method is also slow. But I am intrigued how method #1 can smash methods 3, 4 and 5, some of them in theory process stuff on the GPU.</p>
  
  <p>Method #3 for example, took 2 seconds to resize a 1024x1024 image to 100x100. On the other hand #1 took 0.01 seconds!</p>
  
  <p>Am I missing something?</p>
  
  <p>Something must be wrong or Apple would not take time to write accelerate and CIImage stuff.</p>
  
  <p><strong>NOTE</strong>: I am measuring the time from the time the image is already loaded on a variable to the time a scaled version is saved to another variable. I am not considering the time it takes to read from the file.</p>