Jeg utviklet en endelig løsning for bildeskalering i Swift.
Du kan bruke den til å endre størrelsen på bildet for å fylle, aspektet fylle eller aspekt passe bestemt størrelse.
Du kan justere bildet til sentrum eller en av fire kanter og fire hjørner.
Og også kan du trimme ekstra plass som er lagt til dersom sideforhold på originalbildet og målet størrelse er ikke like.
enum UIImageAlignment {
case Center, Left, Top, Right, Bottom, TopLeft, BottomRight, BottomLeft, TopRight
}
enum UIImageScaleMode {
case Fill,
AspectFill,
AspectFit(UIImageAlignment)
}
extension UIImage {
func scaleImage(width width: CGFloat? = nil, height: CGFloat? = nil, scaleMode: UIImageScaleMode = .AspectFit(.Center), trim: Bool = false) -> UIImage {
let preWidthScale = width.map { $0 / size.width }
let preHeightScale = height.map { $0 / size.height }
var widthScale = preWidthScale ?? preHeightScale ?? 1
var heightScale = preHeightScale ?? widthScale
switch scaleMode {
case .AspectFit(_):
let scale = min(widthScale, heightScale)
widthScale = scale
heightScale = scale
case .AspectFill:
let scale = max(widthScale, heightScale)
widthScale = scale
heightScale = scale
default:
break
}
let newWidth = size.width * widthScale
let newHeight = size.height * heightScale
let canvasWidth = trim ? newWidth : (width ?? newWidth)
let canvasHeight = trim ? newHeight : (height ?? newHeight)
UIGraphicsBeginImageContextWithOptions(CGSizeMake(canvasWidth, canvasHeight), false, 0)
var originX: CGFloat = 0
var originY: CGFloat = 0
switch scaleMode {
case .AspectFit(let alignment):
switch alignment {
case .Center:
originX = (canvasWidth - newWidth) / 2
originY = (canvasHeight - newHeight) / 2
case .Top:
originX = (canvasWidth - newWidth) / 2
case .Left:
originY = (canvasHeight - newHeight) / 2
case .Bottom:
originX = (canvasWidth - newWidth) / 2
originY = canvasHeight - newHeight
case .Right:
originX = canvasWidth - newWidth
originY = (canvasHeight - newHeight) / 2
case .TopLeft:
break
case .TopRight:
originX = canvasWidth - newWidth
case .BottomLeft:
originY = canvasHeight - newHeight
case .BottomRight:
originX = canvasWidth - newWidth
originY = canvasHeight - newHeight
}
default:
break
}
self.drawInRect(CGRectMake(originX, originY, newWidth, newHeight))
let image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return image
}
}
Det finnes eksempler på anvendelsen av denne løsningen nedenfor.
Grå rektangelet er målområde bilde vil bli endret til. Blå sirkler i lys blå firkant er bildet (jeg brukte sirkler fordi det er lett å se når det skaleres uten bevare aspektet). Lys oransje fargen markerer områder som vil bli trimmet hvis du passerer trim: true.
Aspect passe før og etter skalering:

Et annet eksempel på aspekt fit :

Aspect passe med toppjustering:

Aspect fill :

Fyll :

Jeg brukte oppskalering i mine eksempler fordi det er enklere å demonstrere, men løsningen fungerer også for nedskalering som i spørsmålet.
For JPEG-komprimering bør du bruke denne:
let compressionQuality: CGFloat = 0.75 // adjust to change JPEG quality
if let data = UIImageJPEGRepresentation(image, compressionQuality) {
// ...
}
Du kan sjekke ut min kjerne med Xcode lekeplass.