Статьи

Применение фотофильтров с базовым изображением в Swift

Конечный продукт
Что вы будете создавать

Core Image — это технология обработки и анализа изображений, разработанная для обеспечения практически непрерывной обработки фотографий и видеоизображений в iOS и OS X. Apple создала несколько великолепных готовых фотоэффектов, которые вы можете легко использовать в своих приложениях для фотосъемки с помощью такие имена, как Instant, Process, Sepia, Tonal и т. д.

Библиотека разработчиков iOS дает хорошее объяснение обработки изображений Core Image в Базовой коллекции ссылок на Core Image .

Я предлагаю вам также проверить страницу Справочника по CIFilter изображений , чтобы получить полный список доступных CIFilter . Обратите внимание, что не все из них совместимы с iOS; некоторые из них работают только на OS X.

Мы будем использовать следующие фильтры Core Image:

  • CIPhotoEffectChrome
  • CISepiaTone
  • CIPhotoEffectTransfer
  • CIPhotoEffectTonal
  • CIPhotoEffectProcess
  • CIPhotoEffectNoir
  • CIPhotoEffectInstant
  • CIPhotoEffectFade

Замечания: Это руководство написано с использованием Xcode 7.3 и Swift 2.2 с целевым значением развертывания 8.0, поэтому ваше приложение будет работать и на старых устройствах.

Откройте Xcode и создайте новый проект, iOS Single View Application . Выберите Swift в качестве языка и Универсальный для устройств. Вы получите пустой UIViewController в раскадровке и пару файлов .swift : ViewController.swift и AppDelegate.swift .

Выберите контроллер в раскадровке и установите его размер на iPhone 3,5 дюйма на правой панели в разделе « Имитированные метрики» . Это поможет вам адаптировать представления для iPhone 4S, устройства Apple с наименьшим доступным размером экрана.

Установить размер контроллера для iPhone 4S

Мы не будем использовать Auto Layout в этом руководстве, потому что оно портит макеты на больших устройствах, таких как iPad и iPad Pro. Отключите его, выбрав « Инспектор файлов» и снимите флажок « Использовать автоматическую компоновку» . Затем нажмите кнопку « Отключить классы размеров» во всплывающем окне.

Отключить автоматическое расположение и классы размеров

Теперь найдите изображение JPEG — либо из Интернета, либо с вашего Mac — и перетащите его под папку Assets.xcassets на панели навигатора проекта. Мы будем использовать это как пример изображения, к которому мы можем применить наши фильтры. Назовите этот файл picture.jpg ; мы назовем это позже в коде.

Вам придется перетащить несколько дополнительных видов в контроллер. Выберите библиотеку объектов в правом нижнем углу Xcode и перетащите UIView в центр экрана. Измените размер изображения до 320 x 320 пикселей и отцентрируйте его по горизонтали.

Теперь добавьте два UIImageView на вашу раскадровку, найдя их в библиотеке объектов и перетащив их в основной UIView . Измените размеры этих изображений, чтобы заполнить этот основной вид (мы рассмотрим, как настроить их свойства автоматического изменения размера позже). Назначьте файл picture.jpg первому представлению изображения с помощью панели инспектора атрибутов.

Присвойте изображение jpg первому UIImageView

Затем перетащите UIScrollView в нижнюю часть экрана и установите его ширину, соответствующую ширине контроллера. Вы также можете добавить UILabel в верхнюю часть контроллера и установить для него текст Filters . Это будет название вашего приложения.

Наконец, добавьте UIButton в верхний левый угол экрана и сделайте заголовок Сохранить .

Размер инспектора Панель можно отобразить, нажав на маленькую иконку линейки в правом верхнем углу экрана. Сделайте это сейчас и начните редактировать размеры вида, выбрав UIButton . Инспектор размера покажет вам координаты x и y на экране (имейте в виду, что x равно 0 в левой части экрана, а y — 0 в верхней части). Установите ширину и высоту до 44 пикселей.

Установить размер кнопки Сохранить и поле

Установите маску авторазмера кнопки, чтобы прикрепить ее к верхней и левой сторонам экрана.

Теперь выберите все другие виды, один за другим, и отрегулируйте их размер и положение следующим образом:

Установить заголовок Размер этикетки и поля

Название приложения имеет ширину 320 пикселей и высоту 44 пикселя и прикрепляется к верхней части экрана.

Установите размер изображения и поля

Каждое изображение имеет ширину и высоту 320 пикселей.

Установите размер ScrollView и поля

Наконец, представление прокрутки (для параметров фильтра) имеет ширину 320 пикселей и высоту 80 пикселей.

Одной из самых приятных особенностей XCode является возможность разделить рабочее пространство на две части и иметь раскадровку на одной стороне и файл Swift на другой стороне. Чтобы сделать это, вы должны щелкнуть значок Assistant Editor в правом верхнем углу окна Xcode:

Значок помощника редактора

Если ваш ViewController выбран в раскадровке, в правой части автоматически отобразится его относительный файл .swift . Если этого не произойдет, вы можете попробовать щелкнуть горизонтальное меню в верхней части файла swift и переключить Manual на Automatic :

Найдите файл Swift для контроллеров в правой части окна XCode

Теперь давайте приложим некоторые из наших представлений к файлу ViewController.swift . На панели « Структура документа» выберите UIView который содержит два UIImageView , удерживайте нажатой клавишу « Control» (или правую кнопку мыши) и перетащите указатель мыши внизу, чтобы получить объявление класса вашего контроллера представления.

Отпустите кнопку мыши, и появится всплывающее окно. Введите имя UIViewcontainerView — и нажмите кнопку Подключиться .

Вы только что добавили объявление для IBOutlet типа UIView в свой файл .swift . Сделайте то же самое для других видов изображений: перетащите синюю линию ниже каждого экземпляра, который вы объявите, и назовите первый originalImage а второй imageToFilter . Убедитесь, что в качестве изображения используется originalImage с изображением picture.jpg .

Затем подключите UIScrollView и назовите его filtersScrollView . Это сохранит все кнопки для применения фильтров к вашей картинке.

Мы объявим нашу UIButton позже как IBAction . Эта кнопка позволит нам сохранить наше отфильтрованное изображение в библиотеке фотографий нашего устройства.

В Swift вы можете объявить глобальные переменные, просто поместив их вне объявления class , в нашем случае это:

1
class ViewController: UIViewController {

Нам нужно создать массив имен CIFilter :

01
02
03
04
05
06
07
08
09
10
var CIFilterNames = [
    «CIPhotoEffectChrome»,
    «CIPhotoEffectFade»,
    «CIPhotoEffectInstant»,
    «CIPhotoEffectNoir»,
    «CIPhotoEffectProcess»,
    «CIPhotoEffectTonal»,
    «CIPhotoEffectTransfer»,
    «CISepiaTone»
]

Как упоминалось в начале этого урока, мы должны использовать исходные имена фильтров Core Image, чтобы наше приложение распознало их. Мы назначим эти фильтры кнопкам, которые создадим позже, чтобы применить фильтр к нашему изображению.

В большинстве случаев вы можете скрыть строку состояния с экрана. Начиная с Xcode 7.0, больше невозможно установить скрытое свойство viewDidLoad() состояния в Info.plist , поэтому вы должны добавить этот метод прямо над viewDidLoad() :

1
2
3
override func prefersStatusBarHidden() -> Bool {
    return true
}

Метод viewDidLoad() — это экземпляр по умолчанию, который Xcode создает каждый раз, когда вы добавляете файл .swift в свой проект; он вызывается, когда экран и все его виды загружаются. Если вы хотите выполнить какое-либо действие еще до того, как это произойдет, вы можете использовать viewDidAppear() или viewWillAppear() , но нам это не нужно. Итак, давайте добавим несколько переменных типа CGFloat прямо под super.viewDidLoad() :

1
2
3
4
5
6
7
8
override func viewDidLoad() {
   super.viewDidLoad()
    
   var xCoord: CGFloat = 5
   let yCoord: CGFloat = 5
   let buttonWidth:CGFloat = 70
   let buttonHeight: CGFloat = 70
   let gapBetweenButtons: CGFloat = 5

Эти значения необходимы для размещения ряда кнопок внутри нашего filtersScrollView . Как видно из приведенного выше кода, xCoord — это позиция X, в которой будет размещена кнопка, yCoord — это позиция Y, buttonWidth и buttonHeight — ее размер, а gapBetweenButtons — это пространство между каждой кнопкой.

Теперь нам нужно создать кнопки с помощью цикла for , который продублирует пользовательскую UIButton и поместит ее в filtersScrollView на основе приведенных выше значений.

Поместите этот код прямо под экземплярами CGFloat :

01
02
03
04
05
06
07
08
09
10
11
12
13
14
var itemCount = 0
        
   for i in 0..<CIFilterNames.count {
       itemCount = i
            
       // Button properties
       let filterButton = UIButton(type: .Custom)
       filterButton.frame = CGRectMake(xCoord, yCoord, buttonWidth, buttonHeight)
       filterButton.tag = itemCount
       filterButton.addTarget(self, action: #selector(ViewController.filterButtonTapped(_:)), forControlEvents: .TouchUpInside)
       filterButton.layer.cornerRadius = 6
       filterButton.clipsToBounds = true
        
       // CODE FOR FILTERS WILL BE ADDED HERE…

Давайте посмотрим, что происходит в этом коде. itemCount — это переменная, которую мы будем использовать позже, чтобы добавить кнопки фильтров в качестве filtersScrollView . Вы можете заметить, что мы объявили эту переменную с префиксом var . Это потому, что он будет изменен циклом for . Если вы хотите объявить константы в Swift, вы используете префикс let , как мы делали для filterButton .

Используя новый синтаксис цикла for Swift 2.2, нам больше не нужно писать i++ . Цикл будет автоматически увеличивать i , считая от 0 до количества элементов в массиве CIFilterNames .

Внутри цикла for мы создаем пользовательскую кнопку, устанавливаем ее значения CGRect , присваиваем ей тег и добавляем к нему целевое действие, которое вызывает функцию, которую мы увидим позже: filterButtonTapped() .

Чтобы наша кнопка выглядела красиво, с закругленными углами, мы используем свойство layer и устанавливаем его угловой радиус равным 6. Затем мы обрезаем изображение, которое будет содержаться в его границах, в противном случае оно будет покрывать закругленные углы.

Следующий фрагмент кода должен быть добавлен под комментарием к предыдущему:

1
2
3
4
5
6
7
8
9
// Create filters for each button
       let ciContext = CIContext(options: nil)
       let coreImage = CIImage(image: originalImage.image!)
       let filter = CIFilter(name: «\(CIFilterNames[i])» )
       filter!.setDefaults()
       filter!.setValue(coreImage, forKey: kCIInputImageKey)
       let filteredImageData = filter!.valueForKey(kCIOutputImageKey) as!
       let filteredImageRef = ciContext.createCGImage(filteredImageData, fromRect: filteredImageData.extent)
       let imageForButton = UIImage(CGImage: filteredImageRef);

Здесь мы инициализируем CIContext и CIImage чтобы Core Image работал с originalImage ( picture.jpg ), который будет отображаться каждой кнопкой. Затем мы CIFilter переменную фильтра типа CIFilter которая будет вызываться каждой кнопкой в ​​цикле for на CIFilterNames массива CIFilterNames .

Наш экземпляр filter должен установить свое состояние по умолчанию, а затем он становится ключом ввода для изображений. Затем мы создаем объект данных из него и его ссылку на изображение, которое мы будем использовать для создания UIImage который будет прикреплен к кнопке.

Поскольку фильтры, которые мы выбрали для этого урока, уже сделаны Apple, нам не нужно применять какие-либо дополнительные значения (например, интенсивность, цвет и т. Д.). Если вы хотите получить информацию о других CIFilters , вы можете проверить страницу справки по CIFilters основного изображения .

В последней строке этого раздела мы наконец установили фоновое изображение кнопки, которое мы создали ранее.

1
2
// Assign filtered image to the button
       filterButton.setBackgroundImage(imageForButton, forState: .Normal)

Еще несколько строк для завершения нашего viewDidLoad() :

01
02
03
04
05
06
07
08
09
10
// Add Buttons in the Scroll View
        xCoord += buttonWidth + gapBetweenButtons
        filtersScrollView.addSubview(filterButton)
    } // END FOR LOOP
         
         
    // Resize Scroll View
    filtersScrollView.contentSize = CGSizeMake(buttonWidth * CGFloat(itemCount+2), yCoord)
 
} // END viewDidload()

Мы добавляем кнопки в качестве вложенных видов в filtersScrollView зависимости от их положения, ширины и расстояния, которые они должны хранить между собой. Затем, наконец, мы закрываем цикл for .

Наконец, мы должны установить contentSize нашего ScrollView чтобы соответствовать всем кнопкам. Здесь мы наконец используем itemCount ранее переменную itemCount , преобразованную в CGFloat (потому что CGSizeMake не принимает значения Int ).

Мы почти закончили, всего несколько строк кода!

В классе ViewController вне viewDidLoad() создайте filterButtonTapper() . Это будет вызываться каждый раз, когда вы нажимаете на одну из кнопок, которые мы создали ранее.

1
2
3
4
5
func filterButtonTapped(sender: UIButton) {
    let button = sender as UIButton
         
    imageToFilter.image = button.backgroundImageForState(UIControlState.Normal)
}

UIButton нам нужно создать экземпляр UIButton , а затем установить изображение imageToFilter на основе фонового изображения этой кнопки, которое уже отфильтровано кодом, помещенным в viewDidLoad() .

Убедитесь, что UIImageView именем imageToFilter перекрывает originalImage , как показано ниже, в противном случае приложение не покажет вам обработанное изображение, потому что исходное изображение скрывает его.

imageToFilter должен быть перед originalImage

Мы подошли к концу этого урока, и есть еще одна функция, которую нужно добавить в ваш файл .swift . Это кнопка «Сохранить», которую мы ранее поместили в раскадровку. Удерживая Control и кнопку мыши, перетащите синюю линию от UIButton на пустое место в вашем классе, отпустите кнопку мыши, и появится новое всплывающее окно. Здесь вы должны изменить тип соединения на Action и ввести имя вашего метода — в данном случае savePicButton — и нажать кнопку Connect .

Объявите IBAction для кнопки Сохранить

На этот раз вы создали IBAction , и вот код, который необходимо поместить в него:

1
2
3
4
5
6
7
8
// Save the image into camera roll
   UIImageWriteToSavedPhotosAlbum(imageToFilter.image!, nil, nil, nil)
        
   let alert = UIAlertView(title: «Filters»,
               message: «Your image has been saved to Photo Library»,
               delegate: nil,
               cancelButtonTitle: «OK»)
   alert.show()

Первая строка просто сохраняет изображение, содержащееся в imageToFilter непосредственно в библиотеке фотографий вашего устройства или в iOS Simulator. Затем мы UIAlertView простой UIAlertView который подтверждает, что операция была выполнена.

Хорошо, давайте запустим наше приложение и посмотрим, что произойдет, если мы нажмем кнопки внизу. Если вы все сделали правильно, ваше приложение должно выглядеть так:

Приложение показывает изображение с применением цветового фильтра
Приложение показывает изображение с применением цветового фильтра
Приложение показывает сообщение о том, что изображение было сохранено в библиотеке фотографий

Спасибо за чтение, и увидимся в следующий раз! Пожалуйста, ознакомьтесь с другими нашими руководствами по разработке приложений для Swift и iOS.

  • IOS
    Начните свою карьеру в iOS с этих 6 курсов
    Эндрю Блэкман
  • стриж
    iOS с нуля с помощью Swift: Swift в двух словах
    Барт Джейкобс
  • стриж
    Чего ожидать от Swift 3
    Барт Джейкобс