In diesem Lernprogramm erfahren Sie, wie Sie mit GPUImage Bildfilter in Echtzeit anwenden, während der Kamera-Feed des Geräts angezeigt wird. Auf dem Weg erfahren Sie, wie Sie Bilder innerhalb eines Karussellcontrollers automatisch auffüllen und die Größe von Bildern mit UIImage + Categories ändern.
Dieses Tutorial baut auf einem früheren Beitrag mit dem Titel "Erstellen einer Foto-App mit GPUImage" auf. In der vorherigen Lektion wurde die Verwendung demonstriert UIImagePickerController
So wählen Sie Fotos aus dem Fotoalbum oder der Kamera des Geräts aus GPUImage
Bibliothek zu Ihrem Projekt und zur Verwendung der GPUImageFilter
Klasse, um die Standbilder der Kamera zu verbessern. Wenn Sie bereits vertraut sind UIImagePickerController
und kann herausfinden, wie man hinzufügt GPUImage
Um Ihr Projekt auf eigene Faust zu erreichen, sollten Sie in der Lage sein, an der Stelle zu beginnen, an der das letzte Tutorial gerade aufgehört hat.
Bei diesem Projekt wird ein Open-Source-Projekt namens iCarousel umfassend genutzt, um ausgewählte Fotos stilvoll darzustellen.
Um iCarousel in Ihr Projekt aufzunehmen, besuchen Sie die offizielle GitHub-Seite und laden Sie den Quellcode als ZIP-Datei herunter. Extrahieren Sie den Code aus der ZIP-Datei und ziehen Sie den Ordner mit dem Titel "iCarousel" in den Xcode Project Navigator. Dieser Ordner sollte beides enthalten iCarousel.h und iCarousel.m. Wählen Sie "Gruppen für hinzugefügte Ordner erstellen" aus und aktivieren Sie das Kontrollkästchen neben "Elemente in den Ordner der Zielgruppe kopieren (falls erforderlich)" sowie das Kontrollkästchen neben dem Zielnamen Ihres Projekts im Bereich "Zu Zielen hinzufügen".
Weiter gehts zu ViewController.m und fügen Sie eine Importanweisung für iCarousel hinzu:
#import "ViewController.h" #import "GPUImage.h" #import "iCarousel / iCarousel.h"
Bevor wir unsere Bilder mit iCarousel anzeigen, müssen wir sie auf eine akzeptable Größe verkleinern. Anstatt den gesamten Code dafür von Hand zu schreiben, verwenden wir das hervorragende UIImage + Categories-Projekt, das grundlegende Funktionen für die Größenänderung von Bildern sowie einige andere Bildmanipulations-Tricks bietet.
Spitze: Sie können alternativ das Projekt MGImageUtilities für diese Aufgabe verwenden. Die Implementierungsdetails unterscheiden sich zwar geringfügig, bieten jedoch auch eine hervorragende Unterstützung für die UIImage-Skalierung.Laden Sie das herunter UIImage + Kategorien
Code von GitHub und erstellen Sie eine neue Gruppe mit demselben Namen in Xcode. Ziehen Sie sowohl die Implementierungs- als auch die Header-Datei für UIImage + Alpha
, UIImage + Größe ändern
, und UIImage + RoundedCorner
in dein Projekt. Wählen Sie "Gruppen für hinzugefügte Ordner erstellen" aus und aktivieren Sie das Kontrollkästchen neben "Elemente in den Ordner der Zielgruppe kopieren (falls erforderlich)" sowie das Kontrollkästchen neben dem Zielnamen Ihres Projekts im Bereich "Zu Zielen hinzufügen".
Innerhalb des ViewController.m Datei importieren Sie die Bildkategorien mit der folgenden Codezeile:
#import "ViewController.h" #import "GPUImage.h" #import "iCarousel.h" #import "UIImage + Resize.h"
Wenn der iCarousel-Code in unser Projekt importiert wurde, wechseln Sie zur MainStoryboard.storyboard Datei, um unsere Schnittstelle zu überarbeiten.
Wählen Sie zuerst den Strom aus UIImageView
verbunden mit dem selectedImageView
IBOutlet
und lösche es. Wechseln Sie wieder zu ViewController.m und ändern Sie den Projektcode wie folgt:
@ Eigenschaft (nichtatomisch, schwach) IBOutlet iCarousel * photoCarousel; @ property (nichtatomisch, schwach) IBOutlet UIBarButtonItem * filterButton; @ property (nichtatomisch, schwach) IBOutlet UIBarButtonItem * saveButton; - (IBAction) photoFromAlbum; - (IBAction) photoFromCamera; - (IBAction) saveImageToAlbum; - (IBAction) applyImageFilter: (id) Absender; @end @implementation ViewController @synthesize photoCarousel, filterButton, saveButton;
In Zeile 1 oben ersetzen selectedImageView
Steckdose mit einem iCarousel
Steckdose genannt photoCarousel
. Tauschen Sie auch die Variablen in der synthesize-Anweisung in Zeile 14 oben aus.
Gehen Sie zurück zum Interface Builder und ziehen Sie einen neuen UIView
auf den View Controller. Mit dem Neuen UIView
Klicken Sie im Bereich "Dienstprogramme" auf die Registerkarte "Identitätsinspektor" und setzen Sie den Wert für das Feld "Klasse" auf "iCarousel". Dies teilt dem Interface Builder mit, dass die UIView
Wir haben das Projekt hinzugefügt und sollten als Instanz der Instanz instanziiert werden iCarousel
Klasse.
Stellen Sie jetzt eine Verbindung zwischen dem her photoCarousel
Steckdose gerade erklärt und die UIView
gerade als Unteransicht hinzugefügt.
Wir müssen sowohl die Datenquelle als auch den Delegaten für festlegen photoCarousel
Dies ist auch in Interface Builder möglich. Gehen Sie zuerst zu ViewController.h und erklären, dass dieser View-Controller den entsprechenden Protokollen entspricht:
#einführen#import "iCarousel / iCarousel.h" @interface ViewController: UIViewController
In Zeile 2 importieren wir iCarousel, und in Zeile 4 erklären wir die Konformität sowohl für den Delegierten als auch für die Datenquelle.
Zurück in der Storyboard-Datei können Sie jetzt sowohl die Datenquelle als auch den Delegaten dem View-Controller zuordnen.
Bevor Sie fortfahren, ändern Sie die Hintergrundfarbe des Fensters iCarousel
Blick auf Schwarz.
Okay, noch eine Sache. Wir möchten, dass die iCarousel-Ansicht unterhalb von angezeigt wird UIToolbar
in der Ansichtshierarchie. Sie können dies visuell tun, indem Sie sie einfach in die richtige Reihenfolge im Interface Builder ziehen:
Beachten Sie, wie die iCarousel-Ansicht jetzt vor der Symbolleiste angezeigt wird.
Speichern Sie Ihre Arbeit im Interface Builder.
iCarousel verwendet ein ähnliches Designmuster UITableView
, dass eine Datenquelle verwendet wird, um Eingaben in das Steuerelement einzuspeisen, und ein Delegat wird verwendet, um die Interaktion mit dem Steuerelement abzuwickeln.
Für unser Projekt ist die Datenquelle eine einfache NSMutableArray
"displayImages" genannt. Fügen Sie dies der Klassenerweiterung in hinzu ViewController.m jetzt:
#import "UIImage + Resize.h" @interface ViewController () NSMutableArray * displayImages; @ property (nichtatomisch, schwach) IBOutlet iCarousel * photoCarousel;
Als nächstes möchten wir Speicher für das Array im angegebenen Initializer der Klasse zuordnen. In unserem Fall wird der View-Controller von einem Storyboard aus instanziiert, so dass der richtige Initialisierer vorhanden ist initWithCoder:
. Wenn die Klasse jedoch programmgesteuert von einer XIB aus instanziiert werden soll, wäre dies der richtige Initialisierer initWithNibName: Bundle:
. Um beiden Initialisierungsstilen Rechnung zu tragen, schreiben wir unseren eigenen benutzerdefinierten Initialisierer und rufen ihn von beiden auf:
- (void) customSetup displayImages = [[NSMutableArray-Zuordnung] init]; - (id) initWithNibName: (NSString *) nibNameOrNil-Bundle: (NSBundle *) nibBundleOrNil if ((self = [super initWithNibName: nibNameOrNil-Bundle: nibBundleOrNil])) [[self customSetup]; return self; - (id) initWithCoder: (NSCoder *) aDecoder if ((self = [super initWithCoder: aDecoder])) [[self customSetup]; return self;
Jetzt können wir die Datenquelle implementieren und delegieren. Beginnen Sie mit der Datenquellenmethode numberOfItemsInCarousel:
, wie so:
#pragma mark #pragma mark iCarousel DataSource / Delegate / Custom - (NSUInteger) numberOfItemsInCarousel: (iCarousel *) Karussell return [displayImages count];
Dies teilt iCarousel mit, wie viele Bilder angezeigt werden sollen, indem die Anzahl der im Datenquellenarray gespeicherten Bilder betrachtet wird.
Schreiben Sie als Nächstes die Methode, die für jedes im Karussell angezeigte Bild tatsächlich eine Ansicht generiert:
- (UIView *) carousel: (iCarousel *) carousel viewForItemAtIndex: (NSUInteger) Index wiederverwendende Ansicht: (UIView *) view // Neue Ansicht erstellen, wenn keine Ansicht für das Recycling verfügbar ist (view == nil) view = [[UIImageView Alloc] initWithFrame: CGRectMake (0, 0, 300.0f, 300.0f)]; view.contentMode = UIViewContentModeCenter; ((UIImageView *) - Ansicht) .image = [displayImages objectAtIndex: index]; Ansicht zurückkehren;
Dies ist ein guter Anfang, aber es gibt ein sehr wichtiges Problem mit den oben genannten: Die Bilder sollten verkleinert werden, bevor sie an iCarousel geliefert werden. Fügen Sie die folgenden Codezeilen hinzu, um die Methode zu aktualisieren:
- (UIView *) carousel: (iCarousel *) carousel viewForItemAtIndex: (NSUInteger) Index wiederverwendende Ansicht: (UIView *) view // Neue Ansicht erstellen, wenn keine Ansicht für das Recycling verfügbar ist (view == nil) view = [[UIImageView Alloc] initWithFrame: CGRectMake (0, 0, 300.0f, 300.0f)]; view.contentMode = UIViewContentModeCenter; // Intelligente Skalierung auf maximal 250px Breite oder Höhe UIImage * originalImage = [displayImages objectAtIndex: index]; CGSize maxSize = CGSizeMake (250.0f, 250.0f); CGSize targetSize; // Wenn das Bild ein Querformat ist, die Breite auf 250px setzen und die Höhe dynamisch ermitteln, wenn (originalImage.size.width> = originalImage.size.height) float newHeightMultiplier = maxSize.width / originalImage.size.width; targetSize = CGSizeMake (maxSize.width, round (originalImage.size.height * newHeightMultiplier)); // Wenn das Bild Hochformat ist, setzen Sie die Höhe auf 250px und ermitteln Sie dynamisch die Breite else float newWidthMultiplier = maxSize.height / originalImage.size.height; targetSize = CGSizeMake (round (newWidthMultiplier * originalImage.size.width), maxSize.height); // Verändern Sie die Größe des Quellbilds nach unten, um in die Ansicht "iCarousel ((UIImageView *))" zu passen. .Image = [[displayImages objectAtIndex: index] resizedImage: targetSize interpolationQuality: kCGInterpolationHigh]; Ansicht zurückkehren;Profi-Tipp: Verwenden Sie diese Methode in einer Produktions-App? Erwägen Sie, den Code für die Leistung zu verbessern, indem Sie die Bildgröße für einen Hintergrund-Thread ändern und ein separates NSMutableArray beibehalten, das die verkleinerten Bildversionen zwischenspeichert. UPDATE 27.09.2012: Nick Lockwood (Autor von iCarousel) hat ein Projekt namens FXImageView veröffentlicht, das das Laden von Bildern in einem Hintergrundthread automatisch behandelt. Es enthält auch andere nützliche Glocken und Pfeifen wie Schlagschatten und abgerundete Ecken!
Wir haben oben eine maximale Größe von 250px festgelegt entweder die Breite oder Höhe des Bildes, und dann skalieren wir das gegenüberliegende Attribut entsprechend. Dies beschränkt die Proportionen des Bildes und sieht viel schöner aus, als einfach auf ein 250 x 250 Pixel großes Quadrat zu skalieren.
Die beiden oben genannten Methoden sind alles, was iCarousel benötigt, um Bilder anzuzeigen.
Mit den konfigurierten Delegaten- und Datenquellenmethoden ist jetzt ein guter Zeitpunkt zum Einrichten des iCarousel-Objekts in der viewDidLoad
Methode auch:
- (void) viewDidLoad [super viewDidLoad]; // iCarousel-Konfiguration self.photoCarousel.type = iCarouselTypeCoverFlow2; self.photoCarousel.bounces = NEIN;
Mit nur wenigen weiteren Änderungen kann das Projekt Bilder innerhalb eines Karussells anzeigen!
Am Anfang dieses Tutorials haben wir die ersetzt selectedImageView
Eigenschaft mit der photoCarousel
Eigenschaft aktualisiert, die Storyboard-Schnittstelle entsprechend aktualisiert und eine erstellt NSMutableArray
als iCarousel-Datenmodell fungieren. Es gibt jedoch einige Methoden in ViewController.m Es wird immer noch das alte Datenmodell verwendet, durch das das Projekt nicht kompiliert werden kann. Aktualisieren Sie die saveImageToAlbum
Methode wie folgt:
- (IBAction) saveImageToAlbum UIImage * selectedImage = [displayImages objectAtIndex: self.photoCarousel.currentItemIndex]; UIImageWriteToSavedPhotosAlbum (selectedImage, self, @selector (Bild: didFinishSavingWithError: contextInfo :), nil);
Zeile 3 wählt die UIImage
aus dem Datenmodell, das dem aktuellen iCarousel-Index entspricht. Zeile 4 führt den eigentlichen Schreibvorgang mit diesem Image durch.
Gehen Sie als nächstes zum UIImagePickerController
Methode delegieren und Code ändern:
- (void) imagePickerController: (UIImagePickerController *) photoPicker didFinishPickingMediaWithInfo: (NSDictionary *) info self.saveButton.enabled = YES; self.filterButton.enabled = YES; [displayImages addObject: [info valueForKey: UIImagePickerControllerOriginalImage]]; [self.photoCarousel reloadData]; [photoPicker dismissViewControllerAnimated: YES Completion: NULL];
In Zeile 6 oben fügen wir das ausgewählte Foto zum neuen Modell hinzu und in Zeile 8 erzwingen Sie eine Aktualisierung des Karussells.
Nur noch eine Änderung vorzunehmen. Gehen Sie zum Aktionsblatt clickedButtonAtIndex:
Methode und ändern Sie den Code wie folgt:
#pragma mark - #pragma mark UIActionSheetDelegate - (void) actionSheet: (UIActionSheet *) actionSheet clickedButtonAtIndex: (NSInteger) buttonIndex if (buttonIndex == actionSheet.cancelButtonIndex) return; GPUImageFilter * selectedFilter; switch (buttonIndex) case 0: selectedFilter = [[GPUImageGrayscaleFilter-Zuordnung] init]; brechen; Fall 1: selectedFilter = [[GPUImageSepiaFilter-Zuordnung] init]; brechen; Fall 2: selectedFilter = [[GPUImageSketchFilter-Zuordnung] init]; brechen; Fall 3: selectedFilter = [[GPUImagePixellateFilter-Zuordnung] init]; brechen; Fall 4: selectedFilter = [[GPUImageColorInvertFilter Allocation] init]; brechen; Fall 5: selectedFilter = [[GPUImageToonFilter-Zuordnung] init]; brechen; Fall 6: selectedFilter = [[GPUImagePinchDistortionFilter-Zuordnung] init]; brechen; Fall 7: selectedFilter = [[GPUImageFilter-Zuordnung] init]; brechen; Standard: Pause; UIImage * filtersImage = [selectedFilter imageByFilteringImage: [displayImages objectAtIndex: self.photoCarousel.currentItemIndex]]; [displayImages replaceObjectAtIndex: self.photoCarousel.currentItemIndex withObject: gefilterteImage]; [self.photoCarousel reloadData];
Die letzten drei Zeilen dieser Methode filtern das Datenmodellbild, das dem aktuellen Karussellindex entspricht, ersetzen die Karussellanzeige durch dieses Bild und aktualisieren das Karussell.
Wenn alles gut gelaufen ist, sollten Sie das Projekt jetzt kompilieren und ausführen können! Auf diese Weise können Sie Ihre Bilder innerhalb des Karussells und nicht nur in einer Bildansicht anzeigen.
Die App sieht bisher gut aus, aber es wäre schön, wenn der Benutzer ein Foto aus dem Karussell entfernen könnte, nachdem er es dem Display hinzugefügt hat. Kein Problem! Wir können jeden auswählen UIGestureRecognizer
Unterklasse, um dies zu ermöglichen. Für dieses Tutorial habe ich mich für ein Doppeltippen mit zwei Fingern entschieden. Diese Geste ist möglicherweise nicht sofort intuitiv, aber sie lässt sich leicht ausführen, und die zusätzliche Komplexität hilft, das versehentliche Entfernen von Bildern zu verhindern.
Innerhalb des ViewController.m Datei, gehe zum Karussell: viewForItemAtIndex: wiederverwendbarAnsicht:
method und fügen Sie die folgenden Zeilen unmittelbar vor dem Ende der Methode hinzu:
// Verändere die Größe des Quellbilds, damit es gut in die Ansicht iCarousel ((UIImageView *)) passt .image = [[displayImages objectAtIndex: index] resizedImage: targetSize interpolationQuality: kCGInterpolationHigh]; // Doppeltipp mit zwei Fingern löscht ein Bild UITapGestureRecognizer * gesture = [[UITapGestureRecognizer-Zuordnung] initWithTarget: Eigenaktion: @selector (removeImageFromCarousel :)]; gesture.numberOfTouchesRequired = 2; gesture.numberOfTapsRequired = 2; view.gestureRecognizers = [NSArray arrayWithObject: Geste]; Ansicht zurückkehren;
Zeilen 4 - 8 deklarieren ein neues UITapGestureRecognizer
Setzen Sie die Anzahl der Berührungen (d. h. Finger), die zum Auslösen der Geste erforderlich sind, auf 2, und legen Sie auch die Anzahl der erforderlichen Taps auf 2 fest. Kurz bevor wir die Ansicht wieder an das iCarousel-Objekt übergeben, setzen wir das gestureRecognizers
Eigenschaft mit dem neu gebildeten Erkenner.
Beachten Sie, dass diese Gestenerkennung beim Auslösen den Wahlschalter auslöst removeImageFromCarousel:
. Lassen Sie uns das als nächstes implementieren:
- (void) removeImageFromCarousel: (UIGestureRecognizer *) Geste [Geste removeTarget: Eigenaktion: @selector (removeImageFromCarousel :)]; [displayImages removeObjectAtIndex: self.photoCarousel.currentItemIndex]; [self.photoCarousel reloadData];
Zeile 3 entfernt die Geste vom aktuellen Ziel, um zu verhindern, dass während der Verarbeitung mehrere Gesten ausgelöst werden. Die verbleibenden zwei Zeilen sind an dieser Stelle nichts Neues.
Erstellen Sie die App erneut und führen Sie sie erneut aus. Sie sollten jetzt Objekte dynamisch aus dem Karussell entfernen können!
Der Rest dieses Tutorials konzentriert sich auf die Verwendung GPUImageStillCamera
Erstellen eines benutzerdefinierten Kamera-Picker-Steuerelements, mit dem Filter auf den eingehenden Videostream in Echtzeit angewendet werden können. GPUImageStillCamera
arbeitet eng mit einer Klasse namens GPUImageView
. Kamerabilder generiert von GPUImageStillCamera
werden an einen zugewiesenen gesendet GPUImageView
Objekt zur Anzeige für den Benutzer. All dies wird mit der zugrundeliegenden Funktionalität erreicht, die von bereitgestellt wird AV-Gründung
Framework, das programmgesteuerten Zugriff auf Kamera-Frame-Daten bietet.
weil GPUImageView
ist eine Kinderklasse von UIView
, Wir können das gesamte Kameradisplay in unsere eigene Umgebung einbetten UIViewController
Klasse.
Neues hinzufügen UIViewController
Klicken Sie mit der rechten Maustaste auf "PhotoFX" im Projektnavigator und wählen Sie dann aus Neue Datei> Objective-C-Klasse. Benennen Sie die Klasse "MTCameraViewController" und geben Sie "UIViewController" in das Feld "Subclass of" ein.
Klicken Sie auf "Weiter" und dann auf "Erstellen", um den Vorgang abzuschließen.
Gehe zum MTCameraViewController.m Datei und Import GPUImage:
#import "MTCameraViewController.h" #import "GPUImage.h"
Als Nächstes erstellen Sie eine Klassenerweiterung mit den erforderlichen GPUImage-Datenmitgliedern:
@interface MTCameraViewController ()GPUImageStillCamera * stillCamera; GPUImageFilter * filter; @Ende
Zum Schluss gehe zum viewDidLoad:
Methode und fügen Sie den Code hinzu, um die Kameraerfassung zu starten:
- (void) viewDidLoad [super viewDidLoad]; // Erstes Kamerafilterfilter einrichten = [[GPUImageFilter-Zuordnung] init]; [filter preparForImageCapture]; GPUImageView * filterView = (GPUImageView *) self.view; [filter addTarget: filterView]; // Benutzerdefinierte GPUImage-Kamera erstellen stillCamera = [[GPUImageStillCamera-Zuordnung] init]; stillCamera.outputImageOrientation = UIInterfaceOrientationPortrait; [stillCamera addTarget: filter]; // Anzeige des Videokamera-Streams starten [stillCamera startCameraCapture];
Die Zeilen 5 - 9 erstellen ein neues GPUImageView
für die Anzeige des Kameraeinzugs und einer Standardeinstellung GPUImageFilter
Beispiel für das Anwenden eines speziellen Effekts auf die Ansicht. Wir hätten eine der beiden genauso gut benutzen können GPUImageFilter
Unterklassen, wie z GPUImageSketchFilter
, Stattdessen beginnen wir mit dem Standardfilter (d. h. ohne Manipulationen) und lassen den Benutzer später einen Filter dynamisch auswählen.
Die Zeilen 11 - 17 instanziieren die GPU-Kamerainstanz und wenden den zuvor erstellten Filter auf die Kamera an, bevor die Aufnahme gestartet wird.
Bevor der Code aus Schritt 8 funktioniert, müssen Sie den benutzerdefinierten Code hinzufügen MTCameraViewController
Klasse, die gerade im Storyboard des Projekts erstellt wurde.
Öffne das MainStoryboard.storyboard Datei und ziehen Sie einen neuen View Controller aus der Objektbibliothek. Wechseln Sie bei ausgewähltem Objekt zur Registerkarte Identitätsinspektor und setzen Sie den Feldwert "Klasse" auf "MTCameraViewController"..
Ziehen Sie als nächstes eine UIToolbar
Klicken Sie auf den Bildschirm, und legen Sie im Eigenschafteninspektor die Stileigenschaft auf "Black Opaque" fest. Fügen Sie der Symbolleiste dann zwei Schaltflächenelemente mit flexibler Breitenleiste mit einem "Foto aufnehmen" hinzu. UIBarButtonItem
Im Zentrum.
Um diesen View Controller mit dem Anwendungsfluss zu verbinden, klicken Sie mit der rechten Maustaste auf die Schaltfläche "Kamera" im Haupt-View-Controller, und ziehen Sie den ausgelösten Segmentauslass auf den neuen View-Controller:
Wenn Sie dazu aufgefordert werden, wählen Sie als Trennstil "Push".
Wechseln Sie, während das neu hinzugefügte Segue-Objekt ausgewählt ist, zum "Attribute-Inspector" und setzen Sie den Bezeichner auf "pushMTCamera". Fahren Sie fort und stellen Sie sicher, dass "Push" aus der Dropdown-Liste "Style" ausgewählt ist.
Stellen Sie sicher, dass beim Erstellen des Segues die UIImagePicker
wird nicht mehr angezeigt, wenn der Benutzer auf dem ersten Anwendungsbildschirm auf die Kamerataste tippt, indem Sie die Verbindung mit trennen IBAction
ausgang von der photoFromCamera
Methode.
Wählen Sie abschließend die Primäransicht des neu erstellten MTCameraViewControllers. Gehen Sie zum Identitätsinspektor und setzen Sie den Klassenwert auf "GPUImageView"..
Noch nicht perfekt. Wenn Sie jetzt die App erstellen und ausführen, sollten Sie Push ausführen können MTCameraViewController
auf die Ansichtshierarchie und beobachten GPUImageView
Zeigen Sie die Bilder der Kamera in Echtzeit an!
Wir können jetzt die Logik hinzufügen, die zur Steuerung des auf die Kameraanzeige angewendeten Filters erforderlich ist. Gehen Sie zuerst zum viewDidLoad:
Methode innerhalb der MTCameraViewController.m Datei und fügen Sie den Code hinzu, der eine Schaltfläche "Filter" oben rechts im View Controller erstellt:
- (void) viewDidLoad [super viewDidLoad]; // Filter-Schaltfläche zur Schnittstelle hinzufügen UIBarButtonItem * filterButton = [[UIBarButtonItem-Zuordnung] initWithTitle: @ "Filter" -Stil: UIBarButtonItemStylePlain Ziel: Eigenaktion: @selector (applyImageFilter :)]; self.navigationItem.rightBarButtonItem = filterButton;
In Zeile 6 oben erstellen wir einen benutzerdefinierten Code UIBarButtonItem
das wird auslösen applyImageFilter:
wenn ausgewählt.
Erstellen Sie nun die Auswahlmethode:
- (IBAction) applyImageFilter: (id) sender UIActionSheet * filterActionSheet = [[UIActionSheet-Zuordnung] initWithTitle: @ "Filter auswählen" delegate: self cancelButtonTitle: @ "Cancel" destructiveButtonTitles: @ "Skizze", @ "Pixellate", @ "Color Invert", @ "Toon", @ "Pinch Distort", @ "None", nil]; [filterActionSheet showFromBarButtonItem: Sender animiert: JA];
Nach dem Hinzufügen der obigen Informationen wird eine Warnmeldung angezeigt, die besagt, dass der aktuelle View-Controller nicht mit dem übereinstimmt UIActionSheetDelegate
Protokoll. Beheben Sie das Problem jetzt, indem Sie zu gehen MTCameraViewController.h und die Klassendeklaration wie folgt ändern:
#einführen@interface MTCameraViewController: UIViewController @Ende
Vervollständige den Kreis, indem du zurück zu den MTCameraViewController.m Datei und Hinzufügen der Logik, die auf die reagiert UIActionSheet
vorgeführt:
- (void) actionSheet: (UIActionSheet *) actionSheet clickedButtonAtIndex: (NSInteger) buttonIndex // Sichern, wenn die Schaltfläche "Abbrechen" betätigt wurde if (actionSheet.cancelButtonIndex == buttonIndex) return; GPUImageFilter * selectedFilter; [stillCamera removeAllTargets]; [filter removeAllTargets]; switch (buttonIndex) case 0: selectedFilter = [[GPUImageGrayscaleFilter-Zuordnung] init]; brechen; Fall 1: selectedFilter = [[GPUImageSepiaFilter-Zuordnung] init]; brechen; Fall 2: selectedFilter = [[GPUImageSketchFilter-Zuordnung] init]; brechen; Fall 3: selectedFilter = [[GPUImagePixellateFilter-Zuordnung] init]; brechen; Fall 4: selectedFilter = [[GPUImageColorInvertFilter Allocation] init]; brechen; Fall 5: selectedFilter = [[GPUImageToonFilter-Zuordnung] init]; brechen; Fall 6: selectedFilter = [[GPUImagePinchDistortionFilter-Zuordnung] init]; brechen; Fall 7: selectedFilter = [[GPUImageFilter-Zuordnung] init]; brechen; Standard: Pause; filter = selectedFilter; GPUImageView * filterView = (GPUImageView *) self.view; [filter addTarget: filterView]; [stillCamera addTarget: filter];
Die Zeilen 11-12 werden verwendet, um den aktuell ausgewählten Filter zurückzusetzen.
Die Zeilen 15 - 42 oben sollten der Logik in vertraut sein ViewController.m; Wir aktivieren nur die ausgewählte Schaltfläche, um eine Instanz des Korrelationsfilters zu erstellen.
Die Zeilen 44 - 47 nehmen den neu erstellten Filter und wenden ihn auf die GPUImage-Kamera an.
Wenn Sie das Projekt jetzt erstellen und ausführen, sollten Sie sehen, dass der Benutzer mit der neu erstellten Filterschaltfläche GPUImage-Filter in Echtzeit ausprobieren kann!
Nachdem nun die Live-Feed-Filter aktiv sind, besteht der letzte große Schritt in diesem Lernprogramm darin, dem Benutzer zu ermöglichen, Schnappschüsse mit der GPUImage-Kamera zu erstellen und sie anschließend im Fotokarussell des Hauptansicht-Controllers anzuzeigen.
Um dies zu erreichen, übergeben wir Nachrichten zwischen Ansichtssteuerungen unter Verwendung des Delegierungsentwurfsmusters. Insbesondere erstellen wir unser eigenes Protokoll für die formale Delegierung MTCameraViewController
und konfigurieren Sie dann das Hauptfenster ViewController
Klasse, die diesem Protokoll entspricht, um Delegierungsnachrichten zu empfangen.
Um zu beginnen, gehe zu MTViewController.h
und ändern Sie den Code wie folgt:
#einführen@protocol MTCameraViewControllerDelegate - (void) didSelectStillImage: (NSData *) - Image withError: (NSError *) - Fehler; @end @interface MTCameraViewController: UIViewController @property (schwach, nicht atomar) ID-Delegierter; @Ende
Der obige Code deklariert ein formelles Delegatenmuster, das aufgerufen wird MTCameraViewControllerDelegate
in den Zeilen 3-7 und erstellt dann ein Delegate-Objekt in Zeile 11.
Als nächstes wechseln Sie zu MTCameraViewController.m und synthetisieren Sie die Delegate-Eigenschaft:
@implementation MTCameraViewController @synthesize delegate;
Wenn das Protokoll deklariert ist, müssen wir es jetzt in der Hauptsache implementieren ViewController
Klasse. Gehe zu ViewController.h
und füge folgende Zeilen hinzu:
#einführen#import "iCarousel.h" #import "MTCameraViewController.h" @interface ViewController: UIViewController @Ende
Jetzt mach das auf ViewController.m Datei. Wir möchten die Delegate-Eigenschaft zuweisen, wenn der View-Controller instanziiert wird. Da wir Storyboards verwenden, ist der richtige Ort dafür prepareForSegue: Absender:
Methode, die aufgerufen wird, bevor der neue View-Controller auf den Bildschirm gedrückt wird:
- (void) preparForSegue: (UIStoryboardSegue *) Absender Absender: (ID) Absender if ([segue.identifier isEqualToString: @ "pushMTCamera"]) // Legt den Delegaten so fest, dass dieser Controller aufgenommene Fotos empfangen kann. MTCameraViewController * cameraViewController = (MTCameraViewController) *) segue.destinationViewController; cameraViewController.delegate = self;
Als nächstes müssen wir das implementieren didSelectStillImage: withError:
Methode für die MTCameraViewControllerDelegate
Protokoll:
#pragma mark - #pragma mark MTCameraViewController // Diese Delegat-Methode wird aufgerufen, nachdem unsere benutzerdefinierte Kameraklasse ein Foto aufgenommen hat. (void) didSelectStillImage: (NSData *) imageData withError: (NSError *) -Fehler if (! error) UIImage * image = [[UIImage allocation] initWithData: imageData]; [displayImages addObject: image]; [self.photoCarousel reloadData]; self.filterButton.enabled = YES; self.saveButton.enabled = YES; else UIAlertView * alert = [[UIAlertView-Zuordnung] initWithTitle: @ "Capture Error" -Meldung: @ "Foto kann nicht aufgenommen werden." Delegat: nil cancelButtonTitle: @ "OK" otherButtonTitles: nil]; [Alertshow];
Der obige Code konvertiert das NSData
Objekt an die Methode übergeben a UIImage
und laden Sie dann das Fotokarussell erneut.
Zum Schluss müssen wir die Dinge abschließen, indem wir zu zurückkehren MTCameraViewController.m und Hinzufügen im entsprechenden Delegate-Methodenaufruf. Richten Sie zuerst ein ein IBAction
Methode, die einen Kamera-Snap auslöst:
GPUImageFilter * filter; - (IBAction) captureImage: (id) Sender; @Ende
Vor dem Fortfahren, Verbinden Sie diese Methode mit der Schaltfläche "Foto aufnehmen" im MainStoryboard.storyboard Datei.
Fügen Sie schließlich die Implementierung der Methode hinzu:
-(IBAction) captureImage: (id) sender // Deaktivieren, um mehrere Taps während der Verarbeitung zu verhindern. UIButton * captureButton = (UIButton *) sender; captu