Из этого туториала вы узнаете, как применять Instagram-фильтры и специальные эффекты к изображениям с помощью невероятно мощного проекта GPUImage. Попутно вы узнаете, как создать простое приложение для камеры, способное делать новые фотографии или получать доступ к существующим изображениям из фотоальбома.
Project Demo
Выше приведен коллаж из фильтров изображений, применяемых вместе с приложением, которое этот урок научит вас создавать. Исходное изображение из ep.Sos.de на Flickr .
Шаг 1: Запустите новый проект Xcode
Запустите Xcode и создайте новое приложение, используя шаблон Single View.
В этом уроке мы будем использовать раскадровки и автоматический подсчет ссылок, поэтому не забудьте выбрать оба поля. Назовите проект «PhotoFX» и предоставьте уникальный идентификатор компании для тестирования устройства.
Шаг 2. Создайте интерфейс приложения
Интерфейс приложения будет состоять из UINavigationBar
для заголовка приложения на UIView
и кнопке сохранения, UIToolbar
для UIToolbar
альбома, камеры и фильтра, а также UIImageView, настроенного на заполнение аспекта для просмотра и изменения выбранных изображений.
Откройте файл MainStoryboard.storyboard . Выберите UIView
на экране, а затем выберите « Редактор»> « UIView
> «Контроллер навигации» .
Выберите UINavigationController
а затем перейдите к Инспектору атрибутов на панели «Утилиты». Установите в раскрывающемся списке «Верхняя панель» значение «Черная панель навигации», а в строке состояния — «Нет». Чтобы завершить удаление строки состояния, перейдите в файл PhotoFX-Info.plist и добавьте новый ключ с текстом «Панель состояния изначально скрыта». Установите значение «ДА».
Поскольку мы только что перевели наше приложение в шаблон UINavigationController
, теперь вы должны перейти к ViewController.h и добавить следующее объявление делегата:
1
2
3
4
5
|
#import <UIKit/UIKit.h>
@interface ViewController : UIViewController <UINavigationControllerDelegate>
@end
|
Нам это понадобится позже.
Теперь вернитесь к файлу раскадровки и дважды щелкните заголовок в центре UINavigationItem
и замените текст по умолчанию на «PhotoFX».
Перетащите UIBarButtonItem
из библиотеки объектов на UINavigationItem
. Выбрав новый элемент кнопки, перейдите на вкладку «Инспектор атрибутов» панели «Утилиты» и установите для свойства идентификатора кнопки значение «Сохранить». Затем, когда кнопка «Сохранить» все еще выбрана, снимите флажок «Включено» для этой кнопки. Это предотвратит попытку пользователя сохранить изображение перед его загрузкой из фотоальбома или выполнением снимка с помощью камеры (позже мы включим его с кодом).
Вернитесь в библиотеку объектов и перетащите UIToolbar
на главный UIView
. Затем добавьте в общей сложности три объекта UIBarButtonItem
на панели инструментов. Измените текст заголовка для первой кнопки на «Альбом», установите для свойства идентификатора второй значение «Камера» и установите для текста заголовка третьей кнопки значение «Фильтр». Кнопка «Фильтр» должна быть отключена по умолчанию, как и кнопка «Сохранить» сверху.
Чтобы отшлифовать макет панели инструментов, нам нужно выровнять правую кнопку filter
на панели инструментов. Вы можете добиться этого эффекта, используя элемент кнопки «Гибкая клавиша пробела», который можно просто перетащить на панель инструментов из библиотеки объектов.
Обратите внимание, насколько яркий белый UIView
отличается от черной блестящей панели навигации и панели инструментов? Давайте сделаем что-нибудь об этом. Выберите UIView
и установите цвет фона «вольфрам».
Единственное подпредставление, которое осталось добавить, — это основной UIImageView
используемый для отображения изображения пользователя. Перетащите UIImageView
из библиотеки объектов и расположите его по центру между UINavigationItem
и UIToolbar
. Поднимите Инспектор Атрибутов и выберите «Подгонка UIImageView
» в качестве режима UIImageView
в подразделе «Просмотр» Инспектора.
Все основные компоненты интерфейса теперь на месте! Следующим шагом является ViewController
этих элементов из Storyboard к классу ViewController
.
Откройте файл ViewController.m . Добавьте следующие свойства IBOutlet
и методы IBAction
в ViewController
класса ViewController
:
01
02
03
04
05
06
07
08
09
10
11
12
|
@interface ViewController ()
@property(nonatomic, weak) IBOutlet UIImageView *selectedImageView;
@property(nonatomic, weak) IBOutlet UIBarButtonItem *filterButton;
@property(nonatomic, weak) IBOutlet UIBarButtonItem *saveButton;
— (IBAction)photoFromAlbum;
— (IBAction)photoFromCamera;
— (IBAction)applyImageFilter:(id)sender;
— (IBAction)saveImageToAlbum;
@end
|
Итак, зачем создавать свойства IBOutlet
для вида изображения, кнопки фильтра и кнопки сохранения, но не для других компонентов Interface Builder? Ответ в том, что это единственные объекты, к которым нам нужен программный доступ. Доступ к просмотру изображений будет доступен для установки изображений, выбранных пользователем, а кнопки фильтра и сохранения будут доступны для переключения состояния с отключенного на включенное после того, как пользователь выберет изображение или сделает фотографию.
Методы IBAction
должны быть в основном понятными и подключаться непосредственно к селектору UIBarButtonItem
, подразумеваемому каждым именем.
После создания свойств IBOutlet
вы должны синтезировать их, добавив следующую строку кода в класс @implementation
:
1
2
3
|
@implementation ViewController
@synthesize selectedImageView, filterButton, saveButton;
|
Чтобы завершить настройку Interface Builder, сопоставьте каждый из вышеуказанных объектов IBOutlet
и методов IBAction
объявленных с соответствующими компонентами Interface Builder (Нужна помощь в этом? Оставьте вопрос в разделе комментариев ниже). Обязательно сохраните изменения, прежде чем двигаться дальше.
Создав интерфейс приложения, мы готовы приступить к написанию кода!
Шаг 3: Выбор фотографий из альбома
В этом руководстве будет использоваться класс UIImagePickerController
для прямого доступа к изображениям в фотоальбоме пользователя. Использование этого класса наложит браузер модальной галереи вида поверх нашего существующего интерфейса. Когда пользователь выбирает желаемое изображение , средство выбора будет использовать делегирование, чтобы уведомить наш класс ViewController о том, что выбор сделан. Если вы новичок в разработке для iOS, не волнуйтесь, это намного проще, чем может показаться.
В файле ViewController.m добавьте следующую реализацию для метода photoFromAlbum
:
01
02
03
04
05
06
07
08
09
10
11
|
@synthesize selectedImageView, filterButton, saveButton;
— (IBAction)photoFromAlbum
{
UIImagePickerController *photoPicker = [[UIImagePickerController alloc] init];
photoPicker.delegate = self;
photoPicker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
[self presentViewController:photoPicker animated:YES completion:NULL];
}
|
Просто, правда? Теперь нам просто нужно реализовать протокол делегата UIImagePickerController
, чтобы отвечать на выбор изображений. Вы сделаете это на шаге 5 этого урока.
Шаг 4: Фотосъемка с помощью камеры
Существует два основных подхода к фотографированию с помощью камеры устройства. Вы можете использовать UIImagePickerController
для доступа к реализации камеры Apple по умолчанию или создать полностью настраиваемый интерфейс с помощью инфраструктуры AVFoundation. GPUImage фактически основывается на функциональности, предоставляемой AVFoundation, чтобы обеспечить класс специально для этой цели. Однако для этого урока мы будем использовать UIImagePickerController
исключительно для выбора фотографий. В следующем руководстве по GPUImage (которое, вероятно, будет опубликовано в ближайшие 1-3 недели), я покажу вам, как использовать более продвинутые классы GPUImage для достижения этой цели.
Код для фотографирования в этом уроке выглядит следующим образом:
01
02
03
04
05
06
07
08
09
10
|
— (IBAction)photoFromCamera
{
UIImagePickerController *photoPicker = [[UIImagePickerController alloc] init];
photoPicker.delegate = self;
photoPicker.sourceType = UIImagePickerControllerSourceTypeCamera;
[self presentViewController:photoPicker animated:YES completion:NULL];
}
|
Если вы сравните метод выше с методом photoFromAlbum
из шага 3, вы увидите, что единственное отличие состоит в том, установлен ли для sourceType
значение UIImagePickerControllerSourceTypePhotoLibrary
или UIImagePickerControllerSourceTypeCamera
. Из-за этого вы можете легко объединить эти два метода в один. Тем не менее, я решил оставить photoFromCamera
как отдельный метод, так как я буду рефакторинг его для использования AVFoundation
в будущем уроке, и логика должна быть отделена.
Шаг 5: кодирование делегата выбора фотографий
Теперь пользователь может UIImagePickerController
библиотеку устройства или использовать камеру устройства для выбора изображения с помощью UIImagePickerController
. Независимо от того, как пользователь выбирает изображение, следующим шагом является реализация метода делегата, который будет отвечать за размещение этого изображения на экране.
Сначала перейдите к ViewController.h и объявите, что этот класс будет соответствовать UIImagePickerControllerDelegate
:
1
2
3
4
5
|
#import <UIKit/UIKit.h>
@interface ViewController : UIViewController <UINavigationControllerDelegate, UIImagePickerControllerDelegate>
@end
|
Теперь перейдите к ViewController.m и реализуйте imagePickerController:didFinishPickingMediaWithInfo:
метод делегата, вызываемый imagePickerController:didFinishPickingMediaWithInfo:
выбора фотографий при выборе:
01
02
03
04
05
06
07
08
09
10
11
|
— (void)imagePickerController:(UIImagePickerController *)photoPicker didFinishPickingMediaWithInfo:(NSDictionary *)info
{
self.saveButton.enabled = YES;
self.filterButton.enabled = YES;
UIImage *selectedImage = [info valueForKey:UIImagePickerControllerOriginalImage];
[self.selectedImageView setImage:selectedImage];
[photoPicker dismissModalViewControllerAnimated:YES];
}
|
В строках 3-4 выше кнопки «Сохранить» и «Фильтр» включены, потому что теперь у нас есть изображение, на котором можно выполнить эти действия.
Строка 6 создает объект UIImage
с фотографией, выбранной пользователем, а строка 8 устанавливает свойство изображения UIImageViewController
для выбранного изображения, которое будет отображать его на экране.
Наконец, строка 10 отклоняет модальное представление, используемое для выбора фотографии.
Приведенный выше код должен хорошо работать, но есть одно усовершенствование. Вместо простого сохранения изображения, выбранного в selectedImageView
, мы также должны сохранить копию во внутреннем UIImage
данных UIImage
. Это позволит приложению применять каждый выбранный фильтр непосредственно к исходному изображению, а не итеративно накладывать эффекты. Это также позволит пользователю легко вернуться к исходному изображению с отфильтрованной точки зрения. Для этого сначала добавьте объект UIImage
в расширение класса в верхней части ViewController.m :
01
02
03
04
05
06
07
08
09
10
|
#import «ViewController.h»
#import «GPUImage.h»
@interface ViewController ()
{
UIImage *originalImage;
}
@property(nonatomic, weak) IBOutlet UIImageView *selectedImageView;
@property(nonatomic, weak) IBOutlet UIBarButtonItem *filterButton;
|
Затем измените imagePickerController:didFinishPickingMediaWithInfo:
метод следующим образом:
01
02
03
04
05
06
07
08
09
10
11
|
— (void)imagePickerController:(UIImagePickerController *)photoPicker didFinishPickingMediaWithInfo:(NSDictionary *)info
{
self.saveButton.enabled = YES;
self.filterButton.enabled = YES;
originalImage = [info valueForKey:UIImagePickerControllerOriginalImage];
[self.selectedImageView setImage:originalImage];
[photoPicker dismissModalViewControllerAnimated:YES];
}
|
Если вы соберете и запустите проект сейчас, вы сможете выбрать фотографии прямо из альбома устройства!
Шаг 6: Сохранение выбранного изображения
Последнее, что нам нужно сделать перед началом работы с GPUImage, — это позволить пользователям сохранять фотографии, сделанные на камеру устройства. Вы можете сделать это с помощью одной строки кода в методе saveImageToAlbum
:
1
2
3
4
|
— (IBAction)saveImageToAlbum
{
UIImageWriteToSavedPhotosAlbum(self.selectedImageView.image, self, @selector(image:didFinishSavingWithError:contextInfo:), nil);
}
|
Приведенная выше строка кода попытается сохранить изображение в фотоальбоме, но вам потребуется реализовать указанный селектор, чтобы реагировать на успех или неудачу:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
— (void)image:(UIImage *)image didFinishSavingWithError:(NSError *)error contextInfo:(void *)contextInfo
{
NSString *alertTitle;
NSString *alertMessage;
if(!error)
{
alertTitle = @»Image Saved»;
alertMessage = @»Image saved to photo album successfully.»;
}
else
{
alertTitle = @»Error»;
alertMessage = @»Unable to save to photo album.»;
}
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:alertTitle
message:alertMessage
delegate:self
cancelButtonTitle:@»Okay»
otherButtonTitles:nil];
[alert show];
}
|
Вышеуказанные строки кода довольно просты и просто отображают сообщение UIAlertView
уведомляющее пользователя о том, было ли изображение успешно сохранено.
Шаг 7: Добавьте GPUImage к вашему проекту
Добавление GPUImage к вашему проекту немного сложнее, чем вы могли бы ожидать, но для выполнения этого шага потребуется всего несколько минут.
Во-первых, вам необходимо скачать копию GPUImage с официального проекта GitHub . Разархивируйте загруженный файл и откройте папку «framework». Это основные файлы, необходимые для импорта GPUImage в ваш проект. Вместо того, чтобы копировать все это в ваш проект напрямую, используйте Finder, чтобы перейти в папку, в которой вы сохранили ваш проект XCode в шаге 1 (для меня это ~ / Desktop / PhotoFX). Создайте новую папку с именем «Submodules» с дочерней папкой с именем «GPUImage». Теперь скопируйте папку «framework», загруженную с GitHub, и вставьте ее в папку «GPUImage». Затем откройте папку «framework» и выберите файл GPUImage.xcodeproj. Ваш экран должен выглядеть примерно так:
Теперь перетащите файл GPUImage.xcodeproj в Xcode Project Navigator. Если вы сделали это успешно, вы должны увидеть что-то вроде следующего:
После успешного добавления проекта вам нужно добавить GPUImage в качестве зависимости в настройках сборки вашего приложения. Выберите «PhotoFX» в навигаторе проекта, выберите цель «PhotoFX», а затем перейдите на вкладку «Build Phases». Разверните раскрывающийся список «Целевые зависимости» и нажмите значок «+». Выберите «GPUImage» из появившегося списка. Посмотрите на следующее изображение, чтобы понять, как это делается:
Теперь вам нужно перетащить файл libGPUImage.a (находится в Навигаторе проектов XCode в GPUImage.xcodeproj> Продукты ) в раскрывающийся список «Связать двоичные файлы с библиотеками». После этого вы должны увидеть что-то вроде следующего:
Пока вы сосредоточены на раскрывающемся списке «Связать двоичные файлы с библиотеками», добавьте следующие необходимые рамки, нажав кнопку «+» в нижнем левом углу:
- CoreMedia
- CoreVideo
- OpenGLES
- AVFoundation
- QuartzCore
Почти сделано! Следующий шаг — выбрать проект PhotoFX и перейти в «Настройки сборки». Выполните поиск «Пути поиска в заголовке» (вам может потребоваться выбрать кнопку «Все» вместо «Основные», чтобы появилась эта опция), а затем дважды щелкните, чтобы добавить Submodules/GPUImage/framework
во всплывающем диалоговом окне, которое будет появляются. Установите флажок рядом с записью, чтобы указать, что этот путь следует искать рекурсивно. Если вы сделали это правильно, вы должны выглядеть примерно так:
Последний шаг — вернуться к ViewController.m и добавить следующую строку вверху:
1
2
|
#import «ViewController.h»
#import «GPUImage.h»
|
Теперь вы должны быть в состоянии скомпилировать и запустить проект без проблем. Возникли проблемы? Оставьте комментарий ниже.
Шаг 8: Показать список фильтров
GPUImage поставляется с впечатляющим количеством фильтров для использования в ваших приложениях. Для этого урока я выбрал следующий пример, чтобы намочить ноги:
- GPUImageGrayscaleFilter
- GPUImageSepiaFilter
- GPUImageSketchFilter
- GPUImagePixellateFilter
- GPUImageColorInvertFilter
- GPUImageToonFilter
- GPUImagePinchDistortionFilter
Чтобы создать собственный список или просто просмотреть все фильтры, которые предлагает GPUImage, ознакомьтесь с официальной документацией на GitHub .
Чтобы предоставить пользователю приведенный выше список фильтров, мы будем использовать простой UIActionSheet
. applyImageFilter:
метод следующим образом:
01
02
03
04
05
06
07
08
09
10
|
— (IBAction)applyImageFilter:(id)sender
{
UIActionSheet *filterActionSheet = [[UIActionSheet alloc] initWithTitle:@»Select Filter»
delegate:self
cancelButtonTitle:@»Cancel»
destructiveButtonTitle:nil
otherButtonTitles:@»Grayscale», @»Sepia», @»Sketch», @»Pixellate», @»Color Invert», @»Toon», @»Pinch Distort», @»None», nil];
[filterActionSheet showFromBarButtonItem:sender animated:YES];
}
|
Шаг 9: реализовать выбор фильтра
Чтобы ответить на выбор фильтра, нам нужно реализовать UIActionSheetDelegate
. Перейдите к ViewController.h и объявите, что класс будет соответствовать этому делегату следующим образом:
1
2
3
4
5
|
#import <UIKit/UIKit.h>
@interface ViewController : UIViewController <UINavigationControllerDelegate, UIImagePickerControllerDelegate, UIActionSheetDelegate>
@end
|
Теперь вернитесь к ViewController.m и добавьте следующий метод:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
|
— (void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex
{
GPUImageFilter *selectedFilter;
switch (buttonIndex) {
case 0:
selectedFilter = [[GPUImageGrayscaleFilter alloc] init];
break;
case 1:
selectedFilter = [[GPUImageSepiaFilter alloc] init];
break;
case 2:
selectedFilter = [[GPUImageSketchFilter alloc] init];
break;
case 3:
selectedFilter = [[GPUImagePixellateFilter alloc] init];
break;
case 4:
selectedFilter = [[GPUImageColorInvertFilter alloc] init];
break;
case 5:
selectedFilter = [[GPUImageToonFilter alloc] init];
break;
case 6:
selectedFilter = [[GPUImagePinchDistortionFilter alloc] init];
break;
case 7:
selectedFilter = [[GPUImageFilter alloc] init];
break;
default:
break;
}
UIImage *filteredImage = [selectedFilter imageByFilteringImage:originalImage];
[self.selectedImageView setImage:filteredImage];
}
|
Бам! Ваше приложение должно теперь работать как нужно. Как видно из вышесказанного, применение фильтров к существующему изображению с помощью GPUImage не может быть проще. Вам просто нужно создать экземпляр GPUImageFilter
и затем вызвать метод imageByFilteringImage:originalImage
.
Шаг 10: добавь иконку приложения
Это приложение просто нуждается в последней вещи: хорошая иконка док-станции. Благодаря нашему дочернему сайту Psdtuts + я смог найти именно то, что искал:
Выше приведен просто обрезка пикселей 57х57 (без сетчатки) и 114х114 (сетчатка) от конечного эффекта, описанного в книге « Как нарисовать камеру Leica в Photoshop » Мохаммада Джепри.
Чтобы вставить их в ваше приложение, вам просто нужно перетащить их в Xcode Project Navigator.
Заворачивать
В этом уроке только поверхностно рассказано о возможностях GPUImage. Если вам понравилось это руководство или вы думаете, что в будущем вы сможете воспользоваться мощью GPUImage, найдите @bradlarson и поблагодарите его за создание такого замечательного проекта с открытым исходным кодом.
Больше содержимого GPUImage?
Хотите увидеть больше контента о GPUImage и обработке изображений? Если так, дайте мне знать! Вы можете оставить свой отзыв в разделе комментариев ниже ( желательно ) или просто отправить мне сообщение в Twitter ( @markhammonds ).
ОБНОВЛЕНИЕ: я теперь опубликовал второй учебник, который детализирует, как использовать камеру GPUImage и показывать фотографии в галерее.
Улучшение приложения Photo с помощью GPUImage и iCarousel .