Работа с изображениями в Swift (iOS/macOS)
Работа с изображениями — одна из ключевых задач в разработке мобильных и десктопных приложений. В Swift для iOS и macOS существует множество встроенных инструментов, позволяющих загружать, отображать, обрабатывать и сохранять изображения. В этой статье мы подробно рассмотрим основные подходы и API, которые помогут вам эффективно работать с графикой на платформах Apple.
Основные классы для работы с изображениями
В зависимости от платформы используются разные классы:
- iOS/tvOS/watchOS —
UIImage(UIKit) - macOS —
NSImage(AppKit)
Оба класса предоставляют схожие возможности, но имеют различия в API. Для кроссплатформенной разработки можно использовать общие протоколы или расширения.
Загрузка изображений
Самый простой способ — загрузить изображение из ресурсов приложения:
// iOS
let image = UIImage(named: "example")
// macOS
let image = NSImage(named: "example")
Для загрузки из сети используйте URLSession:
guard let url = URL(string: "https://example.com/image.jpg") else { return }
URLSession.shared.dataTask(with: url) { data, response, error in
guard let data = data, error == nil else { return }
DispatchQueue.main.async {
// iOS
let image = UIImage(data: data)
// macOS
let image = NSImage(data: data)
}
}.resume()
Отображение изображений
Для отображения изображений на экране используются соответствующие view-компоненты:
- iOS —
UIImageView - macOS —
NSImageView
// iOS
let imageView = UIImageView(image: UIImage(named: "photo"))
imageView.contentMode = .scaleAspectFit
// macOS
let imageView = NSImageView(image: NSImage(named: "photo"))
imageView.imageScaling = .scaleProportionallyUpOrDown
Обработка изображений с Core Image
Core Image — мощный фреймворк для фильтрации и обработки изображений. Рассмотрим базовый пример применения фильтра:
import CoreImage
func applyFilter(to inputImage: CIImage) -> CIImage? {
guard let filter = CIFilter(name: "CISepiaTone") else { return nil }
filter.setValue(inputImage, forKey: kCIInputImageKey)
filter.setValue(0.8, forKey: kCIInputIntensityKey)
return filter.outputImage
}
// Использование
let originalImage = CIImage(image: UIImage(named: "photo")!)!
if let filteredImage = applyFilter(to: originalImage) {
let context = CIContext()
let cgImage = context.createCGImage(filteredImage, from: filteredImage.extent)
let resultImage = UIImage(cgImage: cgImage!)
}
Популярные фильтры Core Image:
CISepiaTone— сепияCIGaussianBlur— размытие по ГауссуCIColorControls— настройка яркости, контраста, насыщенностиCIVignette— виньетирование
Работа с пикселями и CGImage
Для низкоуровневой работы с пиксельными данными используйте CGImage из Core Graphics:
func pixelColors(from image: UIImage) -> [[UIColor]]? {
guard let cgImage = image.cgImage else { return nil }
let width = cgImage.width
let height = cgImage.height
let colorSpace = CGColorSpaceCreateDeviceRGB()
let bytesPerPixel = 4
let bytesPerRow = bytesPerPixel * width
let bitsPerComponent = 8
var pixelData = [UInt8](repeating: 0, count: width * height * bytesPerPixel)
guard let context = CGContext(data: &pixelData,
width: width,
height: height,
bitsPerComponent: bitsPerComponent,
bytesPerRow: bytesPerRow,
space: colorSpace,
bitmapInfo: CGImageAlphaInfo.premultipliedLast.rawValue)
else { return nil }
context.draw(cgImage, in: CGRect(x: 0, y: 0, width: width, height: height))
var result = [[UIColor]]()
for y in 0..<height {
var row = [UIColor]()
for x in 0..<width {
let offset = (y * width + x) * bytesPerPixel
let red = CGFloat(pixelData[offset]) / 255.0
let green = CGFloat(pixelData[offset + 1]) / 255.0
let blue = CGFloat(pixelData[offset + 2]) / 255.0
let alpha = CGFloat(pixelData[offset + 3]) / 255.0
row.append(UIColor(red: red, green: green, blue: blue, alpha: alpha