UIImage.draw(in:) has a aliasing problem

I have a image with pixel size: 3024 * 3024
I have a custom UIView with logical size: 207 * 207, and layer.contentsScale is 3, so pixel size is 621 * 621.

I want to draw this UIImage in my custom UIView, the code in draw(rect:) like this;

Code Block
var image: UIImage? {
didSet {
setNeedDisplay()
}
}
override func draw(_ rect: CGRect) {
    guard let ctx = UIGraphicsGetCurrentContext() else { return }
    ctx.addRect(bounds)
    ctx.setFillColor(UIColor.black.cgColor)
    ctx.fillPath()
     
    if var im = image {
       let size = Math.getMaxSizeWithAspect(size: CGSize(width: bounds.width, height: bounds.height), radioWidthToHeight: im.size.width / im.size.height)
      
im.draw(in: CGRect(x: (bounds.width - size.width) / 2, y: (bounds.height - size.height) / 2, width: size.width, height: size.height))
}


and the result is very bad, picture is aliasing, I tried much solution, but not work well.

Code Block
// not work list...
ctx.setShouldAntialias(true)
ctx.setAllowsAntialiasing(true)
ctx.interpolationQuality = .high
layer.allowsEdgeAntialiasing = true
layer.minificationFilter = .trilinear



Is Math.getMaxSizeWithAspect a function of yours ?

If so, thanks to post the code.

Also try to change
  • .trilinear with .linear

or
  • 207 in 252 (if that fits in your app)

@Claude31, thank you for your reply, but is not work.

I found the solution

in UIView.draw function
  1. create a CGImageContext with final image pixel size

  2. draw UIImage into CGImageContext

  3. get CGImage from CGImageContext

  4. draw this CGImage into CGContext of UIView.draw

it works well.

there is my code:
Code Block
override func draw(_ rect: CGRect) {
  guard let ctx = UIGraphicsGetCurrentContext() else { return }
// fill background with black color
  ctx.addRect(bounds)
  ctx.setFillColor(UIColor.black.cgColor)
  ctx.fillPath()
   
  if var im = image {
// image pixel size is 4032 * 4032, so aspect is 1:1=1,
// bounds size is logical size (384 * 512), so I need found a max size in bounds and keep my image aspect
// so 'size' is (384 * 384)
    let size = Math.getMaxSizeWithAspect(size: CGSize(width: bounds.width, height: bounds.height), radioWidthToHeight: im.size.width / im.size.height)
// pixelSize = (384 * 3, 384 * 3) = (1152, 1152)
    let pixelSize = CGSize(width: size.width * layer.contentsScale, height: size.height * layer.contentsScale)
// I create a pixelSize ImageContext
    UIGraphicsBeginImageContextWithOptions(pixelSize, true, 1)
    guard let imgCtx = UIGraphicsGetCurrentContext() else { return }
// draw UIImage into ImageContext
    im.draw(in: CGRect(x: 0, y: 0, width: pixelSize.width, height: pixelSize.height))
// get cgImage
    guard let cgImg = imgCtx.makeImage() else { return }
// there is another strange thing, CGContext draw cgImg will show a vertical flip result
// so I have to vertical flip first
    ctx.scaleBy(x: 1, y: -1)
    ctx.translateBy(x: 0, y: -bounds.height)
// draw cgImage into UIView's context
    ctx.draw(cgImg, in: CGRect(x: (bounds.width - size.width) / 2, y: (bounds.height - size.height) / 2, width: size.width, height: size.height))
// it works like charm :D
  }
}

UIImage.draw(in:) has a aliasing problem
 
 
Q