Desarrollé una solución definitiva para el escalado de imágenes en Swift.
Puede usarlo para cambiar el tamaño de la imagen para rellenar, rellenar de aspecto o ajustar el aspecto al tamaño especificado.
Puede alinear la imagen al centro o cualquiera de los cuatro bordes y las cuatro esquinas.
Y también puede recortar el espacio adicional que se agrega si las relaciones de aspecto de la imagen original y el tamaño del objetivo no son iguales.
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
}
}
Hay ejemplos de cómo aplicar esta solución a continuación.
El rectángulo gris es el tamaño de la imagen del sitio de destino. Círculos azules en un rectángulo azul claro es la imagen (usé círculos porque es fácil de ver cuando está escalado sin preservar el aspecto). El color naranja claro marca las áreas que se recortarán si pasa trim: true
.
Ajuste de aspecto antes y después del escalado:
Otro ejemplo de ajuste de aspecto :
Ajuste de aspecto con alineación superior:
Relleno de aspecto :
Llenar :
Utilicé la ampliación en mis ejemplos porque es más fácil de demostrar, pero la solución también funciona para la reducción como en la pregunta.
Para la compresión JPEG, debe usar esto:
let compressionQuality: CGFloat = 0.75 // adjust to change JPEG quality
if let data = UIImageJPEGRepresentation(image, compressionQuality) {
// ...
}
Puedes ver mi esencia con Xcode playground.