Trabajo con imágenes en Swift: resize y crop para iOS y macOS
El procesamiento de imágenes es una de las tareas más comunes en el desarrollo de aplicaciones móviles y de escritorio. En las plataformas de Apple (iOS y macOS) para cambiar el tamaño (resize) y recortar (crop) imágenes se pueden usar tanto frameworks integrados (UIKit para iOS, AppKit para macOS) como el potente framework de bajo nivel Core Graphics. En este artículo analizaremos métodos universales que funcionan en ambas plataformas y proporcionaremos ejemplos de código listos para usar en Swift.
Enfoques principales para el procesamiento de imágenes
Existen tres formas principales de cambiar el tamaño o recortar una imagen en Swift:
- UIKit (iOS/tvOS) — utiliza la clase
UIImagey sus métodosdraw(in:)oUIGraphicsImageRenderer. - AppKit (macOS) — utiliza la clase
NSImagey el trabajo conNSGraphicsContext. - Core Graphics (Quartz 2D) — framework C multiplataforma de bajo nivel que funciona tanto en iOS como en macOS. Está basado en
CGImagey contextos gráficos.
Para mayor versatilidad, usaremos Core Graphics, ya que permite escribir código que se adapta fácilmente a ambas plataformas. Sin embargo, para proyectos de iOS suele ser más conveniente usar UIGraphicsImageRenderer, que es más simple y rápido.
Cambiar el tamaño de la imagen (Resize)
La función resize toma la imagen original (UIImage o NSImage) y un nuevo tamaño (CGSize). El algoritmo es simple: se crea un contexto gráfico del tamaño deseado, se dibuja la imagen original en él y luego se extrae la nueva imagen del contexto.
Ejemplo para iOS (UIKit)
import UIKit
extension UIImage { func resized(to newSize: CGSize) -> UIImage? { let renderer = UIGraphicsImageRenderer(size: newSize) return renderer.image { _ in self.draw(in: CGRect(origin: .zero, size: newSize)) } }}
// Uso:if let image = UIImage(named: "example"), let resized = image.resized(to: CGSize(width: 300, height: 200)) { // usar resized}Ejemplo para macOS (AppKit + Core Graphics)
import AppKit
extension NSImage { func resized(to newSize: NSSize) -> NSImage? { guard let cgImage = self.cgImage(forProposedRect: nil, context: nil, hints: nil) else { return nil } let bitmap = NSBitmapImageRep( bitmapDataPlanes: nil, pixelsWide: Int(newSize.width), pixelsHigh: Int(newSize.height), bitsPerSample: 8, samplesPerPixel: 4, hasAlpha: true, isPlanar: false, colorSpaceName: .deviceRGB, bitmapFormat: .alphaFirst, bytesPerRow: 0, bitsPerPixel: 0 ) guard let context = NSGraphicsContext(bitmapImageRep: bitmap!) else { return nil } NSGraphicsContext.saveGraphicsState() NSGraphicsContext.current = context let rect = NSRect(origin: .zero, size: newSize) self.draw(in: rect, from: .zero, operation: .copy, fraction: 1.0) NSGraphicsContext.restoreGraphicsState() let newImage = NSImage(size: newSize) newImage.addRepresentation(bitmap!) return newImage }}Recorte de imagen (Crop)
El recorte (crop) consiste en extraer un área rectangular de la imagen original. En Core Graphics se utiliza la función cropping(to:) de CGImage. Es importante recordar que las coordenadas en Core Graphics comienzan desde la esquina inferior izquierda, por lo que para iOS (donde el eje Y apunta hacia abajo) puede ser necesaria una transformación de coordenadas.