Construire une application photo avec GPUImage

Ce tutoriel vous apprendra à appliquer des filtres et des effets spéciaux de type Instagram aux images avec le projet incroyablement puissant de GPUImage. En cours de route, vous apprendrez à créer une application simple permettant de prendre de nouvelles photos ou d'accéder aux images existantes de l'album photo..


Démo de projet

Ce qui précède est un collage de filtres d'image appliqués à l'application que ce tutoriel vous apprendra à construire. L'image source provient d'ep.Sos.de sur Flickr.


Étape 1: Démarrer un nouveau projet Xcode

Lancer Xcode et créer une nouvelle application à l'aide du modèle Single View.

Pour ce tutoriel, nous utiliserons à la fois le décompte Storyboards et Automatic Reference, assurez-vous donc de sélectionner les deux cases. Nommez le projet "PhotoFX" et fournissez un identifiant unique pour le test du périphérique..


Étape 2: Créer l'interface d'application

L’interface de l’application consistera en un Barre de navigation pour le titre de l'application sur le UIView et enregistrer le bouton, un UIToolbar pour les boutons de l’album, de la caméra et du filtre, et un UIImageView défini sur le remplissage de l’aspect pour afficher et modifier les images sélectionnées.

Ouvrez le MainStoryboard.storyboard fichier. Sélectionnez le UIView à l'écran, puis sélectionnez Éditeur> Incorporer dans> Contrôleur de navigation.

Sélectionnez le UINavigationController Accédez ensuite à l'inspecteur d'attributs dans le volet Utilitaire. Réglez la "Barre supérieure" sur "Barre de navigation noire" et la "Barre d'état" sur "Aucune". Pour finaliser la suppression de la barre d’état, allez à la PhotoFX-Info.plist fichier et ajoutez une nouvelle clé avec le texte "La barre d’état est initialement masquée". Définissez la valeur sur "OUI".

Parce que nous venons de transformer notre application en un UINavigationController modèle, vous devriez maintenant aller à ViewController.h et ajoutez la déclaration de délégué suivante:

 #importation  @interface ViewController: UIViewController  @fin

On en aura besoin plus tard.

Maintenant, retournez au fichier Storyboard et double-cliquez sur le titre au centre de la UINavigationItem et remplacez le texte par défaut par "PhotoFX".

Faites glisser un UIBarButtonItem de la bibliothèque d'objets sur le UINavigationItem. Avec le nouvel élément de bouton sélectionné, accédez à l'onglet Inspecteur d'attributs du panneau Utilitaires et définissez la propriété Identifiant du bouton sur "Enregistrer". Ensuite, avec le bouton "Enregistrer" toujours sélectionné, décochez la case "Activé" pour ce bouton. Cela empêchera l'utilisateur d'essayer de sauvegarder une image avant d'en charger une dans l'album photo ou de prendre une photo avec l'appareil photo (nous l'activerons avec du code ultérieurement)..

Revenez à la bibliothèque d'objets et faites glisser un UIToolbar sur le principal UIView. Suivant ajouter un total de trois UIBarButtonItem objets sur la barre d'outils. Modifiez le texte du titre du premier bouton sur "Album", définissez la propriété Identifiant du second sur "Caméra" et définissez le titre du troisième bouton sur "Filtre". Le bouton "Filtre" doit être désactivé par défaut, tout comme le bouton "Enregistrer" d'en haut.

Pour peaufiner la présentation de la barre d’outils, nous devons aligner à droite le filtre bouton dans la barre d’outils. Vous pouvez obtenir cet effet en utilisant un élément de bouton de barre d'espace flexible, que vous pouvez simplement faire glisser sur la barre d'outils à partir de la bibliothèque d'objets..

Remarquez comme le blanc UIView est en contraste avec la barre de navigation et la barre d'outils brillantes et noires? Faisons quelque chose à ce sujet. Sélectionnez le UIView et réglez la couleur de fond sur "tungstène".

La seule sous-vue à ajouter est la principale UIImageView utilisé pour afficher l'image de l'utilisateur. Faites glisser un UIImageView de la bibliothèque d'objets et le centrer entre les UINavigationItem et le UIToolbar. Ouvrez l’Inspecteur d’Attributs et sélectionnez "Aspect Fit" comme UIImageView Mode dans la sous-section "Voir" de l'inspecteur.

Tous les principaux composants de l'interface sont maintenant en place! La prochaine étape consiste à câbler ces éléments du Storyboard au ViewController classe.

Ouvrez le ViewController.m fichier. Ajouter ce qui suit IBOutlet propriétés et IBAction méthodes dans le ViewController extension de classe:

 @interface ViewController () @property (nonatomic, faible) IBOutlet UIImageView * selectedImageView; @property (nonatomic, faible) IBOutlet UIBarButtonItem * filterButton; @property (nonatomic, faible) IBOutlet UIBarButtonItem * saveButton; - (IBAction) photoFromAlbum; - (IBAction) photoFromCamera; - (IBAction) applyImageFilter: (id) expéditeur; - (IBAction) saveImageToAlbum; @fin

Alors, pourquoi créer IBOutlet les propriétés de la vue d'image, du bouton de filtrage et du bouton d'enregistrement, mais pas les autres composants Interface Builder? La réponse est que ce sont les seuls objets auxquels nous aurons besoin d'accéder par programme. Vous accédez à la vue d’image pour définir les images sélectionnées par l’utilisateur, tandis que vous accédez aux boutons de filtre et de sauvegarde pour passer de l’état désactivé à l’activation après que l’utilisateur sélectionne une image ou prend une photo.

le IBAction Les méthodes devraient être en grande partie explicites et se connecter directement à la UIBarButtonItem sélecteur impliqué par chaque nom.

Après avoir créé le IBOutlet propriétés, vous devez les synthétiser en ajoutant la ligne de code suivante à la classe @la mise en oeuvre:

 @implementation ViewController @synthesize selectedImageView, filterButton, saveButton;

Pour terminer la configuration d'Interface Builder, mappez chacun des éléments ci-dessus. IBOutlet objets et IBAction méthodes déclarées aux composants Interface Builder appropriés (vous avez besoin d’aide pour cela? Laissez une question dans la section commentaires ci-dessous). Veillez à enregistrer vos modifications avant de poursuivre..

Avec l'interface de l'application créée, nous sommes prêts à commencer à coder la fonctionnalité.!


Étape 3: Sélection des photos de l'album

Ce tutoriel utilisera le UIImagePickerController classe pour accéder directement aux images de l'album photo de l'utilisateur. L'utilisation de cette classe superposera un navigateur de galerie de vues modales au-dessus de notre interface existante. Lorsqu'un utilisateur sélectionne l'image qu'il souhaite, le sélecteur utilisera la délégation pour informer notre ViewController classe qu'une sélection a été faite. Si vous débutez dans le développement iOS, ne vous inquiétez pas, c'est beaucoup plus facile que cela puisse paraître.

dans le ViewController.m fichier, ajoutez l'implémentation suivante pour le photoFromAlbum méthode:

 @synthesize selectedImageView, filterButton, saveButton; - (IBAction) photoFromAlbum UIImagePickerController * photoPicker = [[UIImagePickerController alloc] init]; photoPicker.delegate = self; photoPicker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary; [self presentViewController: photoPicker animé: YES complétion: NULL]; 

Simple, non? Maintenant, nous avons juste besoin de mettre en œuvre le UIImagePickerController déléguer le protocole afin de répondre aux sélections d'images. Vous ferez cela à l'étape 5 de ce tutoriel..


Étape 4: Prendre des photos avec l'appareil photo

Il existe deux approches principales pour prendre des photos avec l'appareil photo du périphérique. Vous pouvez soit utiliser le UIImagePickerController pour accéder à la mise en œuvre par défaut de la caméra Apple, ou vous pouvez créer une expérience entièrement personnalisée avec le cadre AVFoundation. GPUImage s'appuie en réalité sur la fonctionnalité fournie par AVFoundation pour fournir une classe spécifiquement dans ce but. Cependant, pour ce tutoriel, nous utiliserons UIImagePickerController pour la sélection de photos exclusivement. Dans un prochain tutoriel sur GPUImage (susceptible d'être publié dans les 1 à 3 prochaines semaines), je vais vous montrer comment utiliser les classes plus avancées de GPUImage pour y parvenir..

Le code pour prendre des photos dans ce tutoriel est le suivant:

 - (IBAction) photoFromCamera UIImagePickerController * photoPicker = [[UIImagePickerController alloc] init]; photoPicker.delegate = self; photoPicker.sourceType = UIImagePickerControllerSourceTypeCamera; [self presentViewController: photoPicker animé: YES complétion: NULL]; 

Si vous comparez la méthode ci-dessus avec le photoFromAlbum méthode de l'étape 3, vous verrez que la seule différence est de savoir si Type de Source est réglé sur UIImagePickerControllerSourceTypePhotoLibrary ou UIImagePickerControllerSourceTypeCamera. De ce fait, vous pouvez facilement combiner ces deux méthodes en une. Cependant, j'ai décidé de partir photoFromCamera comme une méthode distincte comme je vais le refactoriser pour utiliser AVFoundation dans un futur tutoriel et la logique devra être séparée.


Étape 5: Codez le délégué Sélecteur de photos

L’utilisateur peut maintenant parcourir la bibliothèque de périphériques ou utiliser l’appareil photo du périphérique pour sélectionner une image avec UIImagePickerController. Quelle que soit la manière dont l'utilisateur sélectionne une image, l'étape suivante consiste à implémenter la méthode de délégation qui sera chargée de placer cette image à l'écran..

D'abord, allez à ViewController.h et déclarer que cette classe sera conforme à UIImagePickerControllerDelegate:

 #importation  @interface ViewController: UIViewController  @fin

Maintenant, retournez à ViewController.m et mettre en œuvre le imagePickerController: didFinishPickingMediaWithInfo: méthode de délégué appelée par le sélecteur de photos lors de la sélection:

 - (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 licencierModalViewControllerAnimated: OUI]; 

Sur les lignes 3 à 4 ci-dessus, les boutons de sauvegarde et de filtrage sont activés, car nous avons maintenant une image sur laquelle ces actions peuvent être effectuées..

La ligne 6 crée un UIImage objet avec la photo sélectionnée par l'utilisateur, et la ligne 8 définit la propriété image du UIImageViewController à l'image choisie qui l'affichera à l'écran.

Enfin, la ligne 10 supprime la vue modale utilisée pour sélectionner la photo..

Le code ci-dessus devrait bien fonctionner, mais une amélioration est nécessaire. Plutôt que de simplement stocker l’image sélectionnée dans le selectedImageView, nous devrions également conserver une copie dans un document interne UIImage membre de données. Cela permettra à l'application d'appliquer chaque filtre sélectionné directement à l'image d'origine plutôt que de superposer les effets de manière itérative. Cela permettra également à l'utilisateur de revenir facilement à l'image d'origine à partir d'une perspective filtrée. Pour ce faire, ajoutez d’abord un UIImage objecter à l'extension de classe en haut de ViewController.m:

 #import "ViewController.h" #import "GPUImage.h" @interface ViewController () UIImage * originalImage;  @property (nonatomic, faible) IBOutlet UIImageView * selectedImageView; @property (nonatomic, faible) IBOutlet UIBarButtonItem * filterButton;

Ensuite, modifiez le imagePickerController: didFinishPickingMediaWithInfo: méthode comme suit:

 - (void) imagePickerController: (UIImagePickerController *) photoPicker didFinishPickingMediaWithInfo: (NSDictionary *) info self.saveButton.enabled = YES; self.filterButton.enabled = YES; originalImage = [info valueForKey: UIImagePickerControllerOriginalImage]; [self.selectedImageView setImage: originalImage]; [photoPicker licencierModalViewControllerAnimated: OUI]; 

Si vous générez et exécutez le projet maintenant, vous devriez pouvoir sélectionner des photos directement à partir de l'album du périphérique.!


Étape 6: enregistrement de l'image sélectionnée

La dernière chose à faire avant de s'attaquer à GPUImage est de permettre aux utilisateurs d'enregistrer les photos qu'ils prennent avec l'appareil photo du périphérique. Vous pouvez le faire avec une seule ligne de code dans le saveImageToAlbum méthode:

 - (IBAction) saveImageToAlbum UIImageWriteToSavedPhotosAlbum (self.selectedImageView.image, self, @selector (image: didFinishSavingWithError: contextInfo :), nil); 

La ligne de code ci-dessus tentera de sauvegarder l'image dans l'album photo, mais vous devrez implémenter le sélecteur spécifié afin de répondre en cas de succès ou d'échec:

 - (void) image: (UIImage *) image didFinishSavingWithError: (NSError *) erreur contextInfo: (void *) contextInfo NSString * alertTitle; NSString * alertMessage; if (! error) alertTitle = @ "Image enregistrée"; alertMessage = @ "Image enregistrée avec succès dans l'album photo.";  else alertTitle = @ "Erreur"; alertMessage = @ "Impossible d'enregistrer dans un album photo.";  UIAlertView * alert = [[UIAlertView alloc] initWithTitle: message alertTitle: délégué alertMessage: auto cancelButtonTitle: @ "d'accord" otherButtonTitles: nil]; [émission d'alerte]; 

Les lignes de code ci-dessus sont plutôt simples et affichent simplement un UIAlertView message notifiant à l'utilisateur si l'image a été enregistrée avec succès ou non.


Étape 7: Ajoutez GPUImage à votre projet

Ajouter GPUImage à votre projet est un peu plus compliqué que prévu, mais si vous suivez cette étape, quelques minutes suffisent pour que vous puissiez être opérationnel..

Tout d’abord, vous devez télécharger une copie de GPUImage à partir du projet officiel GitHub. Désarchivez le fichier téléchargé et ouvrez le dossier "framework". Ce sont les fichiers essentiels nécessaires pour importer GPUImage dans votre projet. Plutôt que de copier tout cela directement dans votre projet, utilisez le Finder pour aller à l'emplacement où vous avez enregistré votre projet Xcode à l'étape 1 (pour moi, ~ / Desktop / PhotoFX). Créez un nouveau dossier appelé "Sous-modules" avec un dossier enfant appelé. "GPUImage". Maintenant, copiez le dossier "framework" téléchargé depuis GitHub et collez-le dans le dossier "GPUImage". Ensuite, ouvrez le dossier "framework" et sélectionnez le fichier GPUImage.xcodeproj. Votre écran devrait ressembler à ceci:

Faites maintenant glisser le fichier GPUImage.xcodeproj dans le navigateur de projet Xcode. Si vous avez réussi, vous devriez voir quelque chose comme ce qui suit:

Une fois le projet ajouté avec succès, vous devez ajouter GPUImage en tant que dépendance dans les paramètres de construction de votre application. Sélectionnez "PhotoFX" dans le navigateur de projet, sélectionnez la cible "PhotoFX", puis sélectionnez l’onglet "Build Phases". Développez la liste déroulante "Dépendances cibles" puis cliquez sur l'icône "+". Sélectionnez "GPUImage" dans la liste qui apparaît. Jetez un oeil à l'image suivante pour avoir une idée de la façon dont cela est fait:

Maintenant, vous devez faire glisser le fichier libGPUImage.a (situé dans le Navigateur de projets de Xcode à GPUImage.xcodeproj> Produits) dans le menu déroulant "Link Binary with Libraries". Ceci fait, vous devriez voir quelque chose comme ce qui suit:

Pendant que vous êtes concentré sur la liste déroulante "Lier les fichiers binaires aux bibliothèques", continuez et ajoutez les cadres requis suivants en cliquant sur le bouton "+" dans le coin inférieur gauche:

  • CoreMedia
  • CoreVideo
  • OpenGLES
  • AVFoundation
  • QuartzCore

Presque fini! L'étape suivante consiste à sélectionner le projet PhotoFX et à accéder à "Paramètres de construction". Recherchez "Chemins de recherche en-tête" (vous devrez peut-être sélectionner le bouton "Tous" au lieu de "Basique" pour que cette option apparaisse), puis double-cliquez pour l'ajouter. Sous-modules / GPUImage / framework dans la boîte de dialogue contextuelle qui apparaîtra. Cochez la case en regard de l'entrée pour indiquer que ce chemin doit faire l'objet d'une recherche récursive. Si vous avez fait cela correctement, vous devriez regarder quelque chose comme ce qui suit:

La dernière étape consiste à revenir à ViewController.m et ajoutez la ligne suivante en haut:

 #import "ViewController.h" #import "GPUImage.h"

Vous devriez maintenant pouvoir compiler et exécuter le projet sans problème. Avoir des problèmes? Laissez un commentaire ci-dessous.


Étape 8: Afficher une liste de filtres

GPUImage est livré avec un nombre impressionnant de filtres à utiliser dans vos applications. Pour ce tutoriel, j'ai sélectionné l'exemple suivant pour nous mouiller les pieds:

  • GPUImageGrayscaleFilter
  • GPUImageSepiaFilter
  • GPUImageSketchFilter
  • GPUImagePixellateFilter
  • GPUImageColorInvertFilter
  • GPUImageToonFilter
  • Filtre de GPUImagePinchDistortion

Pour créer votre propre liste ou simplement voir tous les filtres que GPUImage a à offrir, consultez la documentation officielle sur GitHub.

Afin de présenter la liste de filtres ci-dessus à l'utilisateur, nous allons utiliser un simple UIActionSheet. Mettre en œuvre le applyImageFilter: méthode comme suit:

 - (IBAction) applyImageFilter: (id) expéditeur UIActionSheet * filterActionSheet = [[UIActionSheet alloc]] initWithTitle: @ "Sélectionner un filtre" délégué: auto cancelButtonTitle: @ "Cancel" destructiveButtonTitle: nil otherButtonTitles: @ "Grayscale" @ "Esquisse", @ "Pixellate", @ "Inverser la couleur", @ "Toon", @ "Distorsion du pincement", @ "Aucune", nil]; [filterActionSheet showFromBarButtonItem: expéditeur animé: OUI]; 

Étape 9: Implémenter la sélection du filtre

Afin de répondre à la sélection du filtre, nous devrons mettre en œuvre le UIActionSheetDelegate. Aller à ViewController.h et déclare que la classe se conformera à ce délégué comme suit:

 #importation  @interface ViewController: UIViewController  @fin

Maintenant, retournez à ViewController.m et ajoutez la méthode suivante:

 - (void) actionSheet: (UIActionSheet *) actionSheet clickedButtonAtIndex: (NSInteger) buttonIndex GPUImageFilter * selectedFilter; commutateur (buttonIndex) cas 0: selectedFilter = [[GPUImageGrayscaleFilter alloc] init]; Pause; cas 1: selectedFilter = [[GPUImageSepiaFilter alloc] init]; Pause; cas 2: selectedFilter = [[GPUImageSketchFilter alloc] init]; Pause; cas 3: selectedFilter = [[GPUImagePixellateFilter alloc] init]; Pause; cas 4: selectedFilter = [[GPUImageColorInvertFilter alloc] init]; Pause; cas 5: selectedFilter = [[GPUImageToonFilter alloc] init]; Pause; cas 6: selectedFilter = [[GPUImagePinchDistortionFilter alloc] init]; Pause; cas 7: selectedFilter = [[GPUImageFilter alloc] init]; Pause; défaut: break;  UIImage * filterImage = [selectedFilter imageByFilteringImage: originalImage]; [self.selectedImageView setImage: filterImage]; 

Bam! Votre application devrait maintenant fonctionner comme vous le souhaitez. Comme vous pouvez le constater ci-dessus, appliquer des filtres à une image existante avec GPUImage est on ne peut plus simple. Vous devez simplement instancier un GPUImageFilter puis appelez le imageByFilteringImage: originalImage méthode.


Étape 10: Ajouter une icône d'application

Cette application n'a besoin que d'une dernière chose: une bonne icône de dock. Grâce à notre site sœur Psdtuts +, j'ai pu trouver exactement ce que je cherchais:


Ce qui précède est simplement un recadrage de pixels de 57x57 (sans rétine) et de 114x114 (rétine) du dernier effet décrit dans Comment dessiner un appareil photo Leica dans Photoshop par Mohammad Jeprie.

Pour les intégrer à votre application, il vous suffit de les faire glisser dans le navigateur de projet Xcode..


Emballer

Ce tutoriel vient à peine de donner une idée de ce qui est possible avec GPUImage. Si vous avez apprécié ce tutoriel ou si vous pensez bénéficier de la puissance de GPUImage à l'avenir, trouvez @bradlarson et remerciez-le d'avoir créé un projet aussi génial en open source..


Plus de contenu GPUImage?

Voulez-vous voir plus de contenu sur GPUImage et le traitement d'image? Si oui, faites le moi savoir! Vous pouvez laisser vos commentaires dans la section commentaires ci-dessous (préféré) ou simplement m'envoyer un message sur Twitter (@markhammonds)..

METTRE À JOUR: J'ai maintenant posté un deuxième tutoriel qui explique comment utiliser l'appareil photo GPUImage et afficher des photos dans une galerie..
Améliorer une application photo avec GPUImage et iCarousel.