Работа с изображениями в Swift: полное руководство для iOS и macOS

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Работа с изображениями в 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                    

Рекомендаций