5

I am looking for a way to resize a CIImage to an exact size as I am using a blending CIFilter and need both blended CIImages to be the same size. I need to use a CIFilter to resize the image as it would be cheaper for me in terms of memory and I can't use Core Graphics etc.

I know there is a CILanczosScaleTransform filter available, but it doesn't allow to resize for an exact size, only scale down or scale up.

Is there a way to make a CIImage to be an exact size, using only Core Image?

SmartTree
  • 1,381
  • 3
  • 21
  • 40

2 Answers2

16

The CILanczosScaleTransform has two parameters:

  • scale: The scaling factor to use on the image
  • aspectRatio: The additional horizontal scaling factor to use on the image

Using these two parameters, you can achieve a target image size. Compute the scaling factor for the vertical dimension to get the desired height, then compute the result of this scaling applied to the horizontal dimension. This may not match the target width, so compute the aspect ratio to apply to the scaled width to correct it to the desired target width.

import CoreImage

let context = CIContext()
let imageURL = URL(fileURLWithPath: "sample.jpg")
let sourceImage = CIImage(contentsOf: imageURL, options: nil)
let resizeFilter = CIFilter(name:"CILanczosScaleTransform")!

// Desired output size
let targetSize = NSSize(width:190, height:230)

// Compute scale and corrective aspect ratio
let scale = targetSize.height / (sourceImage?.extent.height)!
let aspectRatio = targetSize.width/((sourceImage?.extent.width)! * scale)

// Apply resizing
resizeFilter.setValue(sourceImage, forKey: kCIInputImageKey)
resizeFilter.setValue(scale, forKey: kCIInputScaleKey)
resizeFilter.setValue(aspectRatio, forKey: kCIInputAspectRatioKey)
let outputImage = resizeFilter.outputImage

My sample image had dimensions (w 2,048 h 1,536). The computed scaling factor was 0.1497395833333333 and aspect ratio 0.6195652173913043 giving the target output dimensions of (w 190 h 230).

gavinb
  • 19,278
  • 3
  • 45
  • 60
  • 1
    Thanks! That works as a charm. The compute part is exactly what I was looking for :) – SmartTree May 04 '20 at 11:43
  • I'm getting unresolved identifier `NSSize`, so I used CGSize, but the resizing is often off by like 1. i.e instead of getting 190x230 always, I might get 189 x 230, etc. – sickerin Aug 10 '20 at 03:20
  • @sickerin `NSSize` is a type alias for `CGSize` so it shouldn't make any difference. What is the source image size? Perhaps it's a rounding error. – gavinb Aug 27 '20 at 12:01
  • @gavinb actually I experience the same issue with final result being off by 1 pixel. I wonder if that can be solved somehow? The source image size is always different. – SmartTree Mar 15 '21 at 19:16
  • @SmartTree What are the source and destination image sizes? – gavinb Mar 29 '21 at 13:37
  • 1
    Also use CIAffineTransform filter – Alisher Feb 17 '22 at 09:38
4

If you want to only expand the canvas and keep the original image, use this

ciimage.clampedToExtent().cropped(to: CGRect(x: 0, y: 0, width: 100, height: 100))

or you might want to scale the entire image, then use this

ciimage.transformed(by: CGAffineTransform(scaleX: 10, y: 10))
Eric Yuan
  • 1,213
  • 11
  • 13