diff --git a/ImageFilter.xcodeproj/project.pbxproj b/ImageFilter.xcodeproj/project.pbxproj index 821b415..731a6fd 100644 --- a/ImageFilter.xcodeproj/project.pbxproj +++ b/ImageFilter.xcodeproj/project.pbxproj @@ -7,14 +7,18 @@ objects = { /* Begin PBXBuildFile section */ + 2987212E1DD1B8F600F378D7 /* TableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2987212D1DD1B8F600F378D7 /* TableViewController.swift */; }; 2987A54F1DCD1BAE001FDF06 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2987A54E1DCD1BAE001FDF06 /* AppDelegate.swift */; }; 2987A5511DCD1BAE001FDF06 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2987A5501DCD1BAE001FDF06 /* ViewController.swift */; }; 2987A5541DCD1BAE001FDF06 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 2987A5521DCD1BAE001FDF06 /* Main.storyboard */; }; 2987A5561DCD1BAE001FDF06 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 2987A5551DCD1BAE001FDF06 /* Assets.xcassets */; }; 2987A5591DCD1BAE001FDF06 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 2987A5571DCD1BAE001FDF06 /* LaunchScreen.storyboard */; }; + 2987A5611DCDAF85001FDF06 /* RGBAImage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2987A5601DCDAF85001FDF06 /* RGBAImage.swift */; }; + 2987A5631DCDE4C8001FDF06 /* ImageProcessor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2987A5621DCDE4C8001FDF06 /* ImageProcessor.swift */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ + 2987212D1DD1B8F600F378D7 /* TableViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TableViewController.swift; sourceTree = ""; }; 2987A54B1DCD1BAE001FDF06 /* ImageFilter.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = ImageFilter.app; sourceTree = BUILT_PRODUCTS_DIR; }; 2987A54E1DCD1BAE001FDF06 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 2987A5501DCD1BAE001FDF06 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; }; @@ -22,6 +26,8 @@ 2987A5551DCD1BAE001FDF06 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 2987A5581DCD1BAE001FDF06 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 2987A55A1DCD1BAE001FDF06 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 2987A5601DCDAF85001FDF06 /* RGBAImage.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RGBAImage.swift; sourceTree = ""; }; + 2987A5621DCDE4C8001FDF06 /* ImageProcessor.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ImageProcessor.swift; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -56,10 +62,13 @@ children = ( 2987A54E1DCD1BAE001FDF06 /* AppDelegate.swift */, 2987A5501DCD1BAE001FDF06 /* ViewController.swift */, + 2987A5601DCDAF85001FDF06 /* RGBAImage.swift */, 2987A5521DCD1BAE001FDF06 /* Main.storyboard */, 2987A5551DCD1BAE001FDF06 /* Assets.xcassets */, 2987A5571DCD1BAE001FDF06 /* LaunchScreen.storyboard */, 2987A55A1DCD1BAE001FDF06 /* Info.plist */, + 2987A5621DCDE4C8001FDF06 /* ImageProcessor.swift */, + 2987212D1DD1B8F600F378D7 /* TableViewController.swift */, ); path = ImageFilter; sourceTree = ""; @@ -91,11 +100,13 @@ isa = PBXProject; attributes = { LastSwiftUpdateCheck = 0730; - LastUpgradeCheck = 0730; + LastUpgradeCheck = 0810; ORGANIZATIONNAME = "Jackson Isaac"; TargetAttributes = { 2987A54A1DCD1BAE001FDF06 = { CreatedOnToolsVersion = 7.3.1; + DevelopmentTeam = M89DBD7R74; + LastSwiftMigration = 0810; }; }; }; @@ -136,6 +147,9 @@ buildActionMask = 2147483647; files = ( 2987A5511DCD1BAE001FDF06 /* ViewController.swift in Sources */, + 2987A5611DCDAF85001FDF06 /* RGBAImage.swift in Sources */, + 2987A5631DCDE4C8001FDF06 /* ImageProcessor.swift in Sources */, + 2987212E1DD1B8F600F378D7 /* TableViewController.swift in Sources */, 2987A54F1DCD1BAE001FDF06 /* AppDelegate.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -176,8 +190,10 @@ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; @@ -222,8 +238,10 @@ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; @@ -242,6 +260,7 @@ IPHONEOS_DEPLOYMENT_TARGET = 9.3; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; TARGETED_DEVICE_FAMILY = "1,2"; VALIDATE_PRODUCT = YES; }; @@ -251,10 +270,15 @@ isa = XCBuildConfiguration; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CODE_SIGN_IDENTITY = "iPhone Developer"; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; INFOPLIST_FILE = ImageFilter/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = com.jacksonisaac.ImageFilter; PRODUCT_NAME = "$(TARGET_NAME)"; + PROVISIONING_PROFILE = ""; + SWIFT_VERSION = 3.0; }; name = Debug; }; @@ -262,10 +286,15 @@ isa = XCBuildConfiguration; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CODE_SIGN_IDENTITY = "iPhone Developer"; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; INFOPLIST_FILE = ImageFilter/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = com.jacksonisaac.ImageFilter; PRODUCT_NAME = "$(TARGET_NAME)"; + PROVISIONING_PROFILE = ""; + SWIFT_VERSION = 3.0; }; name = Release; }; @@ -288,6 +317,7 @@ 2987A55F1DCD1BAF001FDF06 /* Release */, ); defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; }; /* End XCConfigurationList section */ }; diff --git a/ImageFilter.xcodeproj/xcuserdata/jacksonisaac.xcuserdatad/xcschemes/ImageFilter.xcscheme b/ImageFilter.xcodeproj/xcuserdata/jacksonisaac.xcuserdatad/xcschemes/ImageFilter.xcscheme index 871169c..0160dbe 100644 --- a/ImageFilter.xcodeproj/xcuserdata/jacksonisaac.xcuserdatad/xcschemes/ImageFilter.xcscheme +++ b/ImageFilter.xcodeproj/xcuserdata/jacksonisaac.xcuserdatad/xcschemes/ImageFilter.xcscheme @@ -1,6 +1,6 @@ Bool { + func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { // Override point for customization after application launch. return true } - func applicationWillResignActive(application: UIApplication) { + func applicationWillResignActive(_ application: UIApplication) { // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. } - func applicationDidEnterBackground(application: UIApplication) { + func applicationDidEnterBackground(_ application: UIApplication) { // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. } - func applicationWillEnterForeground(application: UIApplication) { + func applicationWillEnterForeground(_ application: UIApplication) { // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background. } - func applicationDidBecomeActive(application: UIApplication) { + func applicationDidBecomeActive(_ application: UIApplication) { // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. } - func applicationWillTerminate(application: UIApplication) { + func applicationWillTerminate(_ application: UIApplication) { // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. } diff --git a/ImageFilter/Assets.xcassets/AppIcon.appiconset/Contents.json b/ImageFilter/Assets.xcassets/AppIcon.appiconset/Contents.json index 36d2c80..eeea76c 100644 --- a/ImageFilter/Assets.xcassets/AppIcon.appiconset/Contents.json +++ b/ImageFilter/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -59,6 +59,11 @@ "idiom" : "ipad", "size" : "76x76", "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "83.5x83.5", + "scale" : "2x" } ], "info" : { diff --git a/ImageFilter/Assets.xcassets/Contents.json b/ImageFilter/Assets.xcassets/Contents.json new file mode 100644 index 0000000..da4a164 --- /dev/null +++ b/ImageFilter/Assets.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/ImageFilter/Assets.xcassets/sample.imageset/Contents.json b/ImageFilter/Assets.xcassets/sample.imageset/Contents.json new file mode 100644 index 0000000..f4d8b74 --- /dev/null +++ b/ImageFilter/Assets.xcassets/sample.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "sample.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/ImageFilter/Assets.xcassets/sample.imageset/sample.png b/ImageFilter/Assets.xcassets/sample.imageset/sample.png new file mode 100644 index 0000000..67595e5 Binary files /dev/null and b/ImageFilter/Assets.xcassets/sample.imageset/sample.png differ diff --git a/ImageFilter/Base.lproj/Main.storyboard b/ImageFilter/Base.lproj/Main.storyboard index 3a2a49b..cbc1c0e 100644 --- a/ImageFilter/Base.lproj/Main.storyboard +++ b/ImageFilter/Base.lproj/Main.storyboard @@ -1,25 +1,253 @@ - - + + + + + - + + + - + - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ImageFilter/ImageProcessor.swift b/ImageFilter/ImageProcessor.swift new file mode 100644 index 0000000..70153f0 --- /dev/null +++ b/ImageFilter/ImageProcessor.swift @@ -0,0 +1,85 @@ +// +// ImageProcessor.swift +// ImageFilter +// +// Created by Jackson Isaac on 05/11/16. +// Copyright © 2016 Jackson Isaac. All rights reserved. +// + +import Foundation + +class ImageProcessor { + var totalRed = 0 + var totalBlue = 0 + var totalGreen = 0 + var pixelCount = 0 + + var imageRGBA:RGBAImage? + + // Constructor + init?(imageRGBA: RGBAImage) { + self.imageRGBA = imageRGBA + pixelCount = imageRGBA.width * imageRGBA.height + countRGBVal() + } + + // Count and store RGB values of the image. + func countRGBVal(){ + // 1a. Loop through each pixel of the image + for y in 0.. RGBAImage { + var newImage = self.imageRGBA! + // Loop through each pixel of the image + for y in 0.. + NSPhotoLibraryUsageDescription + Used to import images using Photo Library. + NSCameraUsageDescription + Used to import images using Camera. CFBundleDevelopmentRegion en CFBundleExecutable diff --git a/ImageFilter/RGBAImage.swift b/ImageFilter/RGBAImage.swift new file mode 100644 index 0000000..0b78aad --- /dev/null +++ b/ImageFilter/RGBAImage.swift @@ -0,0 +1,92 @@ +import UIKit + +public struct Pixel { + public var value: UInt32 + + public var red: UInt8 { + get { + return UInt8(value & 0xFF) + } + set { + value = UInt32(newValue) | (value & 0xFFFFFF00) + } + } + + public var green: UInt8 { + get { + return UInt8((value >> 8) & 0xFF) + } + set { + value = (UInt32(newValue) << 8) | (value & 0xFFFF00FF) + } + } + + public var blue: UInt8 { + get { + return UInt8((value >> 16) & 0xFF) + } + set { + value = (UInt32(newValue) << 16) | (value & 0xFF00FFFF) + } + } + + public var alpha: UInt8 { + get { + return UInt8((value >> 24) & 0xFF) + } + set { + value = (UInt32(newValue) << 24) | (value & 0x00FFFFFF) + } + } +} + +public struct RGBAImage { + public var pixels: [Pixel] + + public var width: Int + public var height: Int + + public init?(image: UIImage) { + guard let cgImage = image.cgImage else { return nil } + + // Redraw image for correct pixel format + let colorSpace = CGColorSpaceCreateDeviceRGB() + + var bitmapInfo: UInt32 = CGBitmapInfo.byteOrder32Big.rawValue + bitmapInfo |= CGImageAlphaInfo.premultipliedLast.rawValue & CGBitmapInfo.alphaInfoMask.rawValue + + width = Int(image.size.width) + height = Int(image.size.height) + let bytesPerRow = width * 4 + + let imageData = UnsafeMutablePointer.allocate(capacity: width * height) + + guard let imageContext = CGContext(data: imageData, width: width, height: height, bitsPerComponent: 8, bytesPerRow: bytesPerRow, space: colorSpace, bitmapInfo: bitmapInfo) else { return nil } + imageContext.draw(cgImage, in: CGRect(origin: CGPoint.zero, size: image.size)) + + let bufferPointer = UnsafeMutableBufferPointer(start: imageData, count: width * height) + pixels = Array(bufferPointer) + + imageData.deinitialize() + imageData.deallocate(capacity: width * height) + } + + public func toUIImage() -> UIImage? { + let colorSpace = CGColorSpaceCreateDeviceRGB() + var bitmapInfo: UInt32 = CGBitmapInfo.byteOrder32Big.rawValue + bitmapInfo |= CGImageAlphaInfo.premultipliedLast.rawValue & CGBitmapInfo.alphaInfoMask.rawValue + + let bytesPerRow = width * 4 + + let imageDataReference = UnsafeMutablePointer(mutating: pixels) + defer { + imageDataReference.deinitialize() + } + let imageContext = CGContext(data: imageDataReference, width: width, height: height, bitsPerComponent: 8, bytesPerRow: bytesPerRow, space: colorSpace, bitmapInfo: bitmapInfo, releaseCallback: nil, releaseInfo: nil) + + guard let cgImage = imageContext?.makeImage() else {return nil} + let image = UIImage(cgImage: cgImage) + + return image + } +} diff --git a/ImageFilter/TableViewController.swift b/ImageFilter/TableViewController.swift new file mode 100644 index 0000000..565d73d --- /dev/null +++ b/ImageFilter/TableViewController.swift @@ -0,0 +1,53 @@ +// +// TableViewController.swift +// ImageFilter +// +// Created by Jackson Isaac on 08/11/16. +// Copyright © 2016 Jackson Isaac. All rights reserved. +// + +import UIKit + +class TableViewController: UIViewController, UITableViewDataSource, UITableViewDelegate { + + /* + * Table View is not set in the beginning as the content may change. + * Its data need to be able to reload and seperate from its presentation. + * Delegate: Delegate actions to the table. (handle actions and UI controls) + * Data Source: Delegate control of the data to the table. (provide data) + * Protocols are added for Delegate + */ + @IBOutlet var tableView: UITableView! + + let filters = [ + "Red", + "Blue", + "Green", + "Yellow", + "Purple", + ] + + override func viewDidLoad() { + super.viewDidLoad() + + // Do any additional setup after loading the view. + tableView.dataSource = self + tableView.delegate = self + } + + func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { + print(filters[indexPath.row]) + } + + func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { + return filters.count + } + + func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { + let cell = tableView.dequeueReusableCell(withIdentifier: "FilterCell", for: indexPath) + + cell.textLabel?.text = filters[indexPath.row] + + return cell + } +} diff --git a/ImageFilter/ViewController.swift b/ImageFilter/ViewController.swift index 9d7b860..6ebc6e0 100644 --- a/ImageFilter/ViewController.swift +++ b/ImageFilter/ViewController.swift @@ -8,18 +8,293 @@ import UIKit -class ViewController: UIViewController { - +class ViewController: UIViewController, UIImagePickerControllerDelegate, UINavigationControllerDelegate { + + var image: UIImage? + var filteredImage: UIImage? + var imageProcessor: ImageProcessor? + + @IBOutlet var compareButton: UIButton! + + @IBOutlet var originalOverlay: UIView! + + // Interface Builer Outlet + @IBOutlet weak var imageView: UIImageView! + @IBOutlet var filteredImageView: UIImageView! + + @IBOutlet var secondaryMenu: UIView! + @IBOutlet var bottomMenu: UIView! + + @IBOutlet var filterButton: UIButton! + override func viewDidLoad() { super.viewDidLoad() // Do any additional setup after loading the view, typically from a nib. + + secondaryMenu.backgroundColor = UIColor.white.withAlphaComponent(0.5) + secondaryMenu.translatesAutoresizingMaskIntoConstraints = false + originalOverlay.translatesAutoresizingMaskIntoConstraints = false + + image = imageView.image + compareButton.isEnabled = false } override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() // Dispose of any resources that can be recreated. } + + override func touchesBegan(_ touches: Set, with event: UIEvent?) { + showOverlayOriginalImage() + } + + override func touchesEnded(_ touches: Set, with event: UIEvent?) { + hideOverlayOriginalImage() + } + + @IBAction func onCompare(_ sender: UIButton) { + if(sender.isSelected) { + hideOverlayOriginalImage() + sender.isSelected = false + } else { + showOverlayOriginalImage() + sender.isSelected = true + } + } + + @IBAction func onNegativeFilter(_ sender: UIButton) { + enableCompareButton() + if(sender.isSelected) { + imageView.image = image + sender.isSelected = false + } else { + if (filteredImage != nil) { + imageProcessor = ImageProcessor(imageRGBA: RGBAImage(image: self.filteredImage!)!) + } else { + imageProcessor = ImageProcessor(imageRGBA: RGBAImage(image: self.image!)!) + } + filteredImage = imageProcessor?.applyFilter("negative").toUIImage() + showFilteredImage(filteredImage: filteredImage!) + + sender.isSelected = true + } + } + + @IBAction func onRedFilter(_ sender: UIButton) { + enableCompareButton() + if(sender.isSelected) { + imageView.image = image + sender.isSelected = false + } else { + if (filteredImage != nil) { + imageProcessor = ImageProcessor(imageRGBA: RGBAImage(image: self.filteredImage!)!) + } else { + imageProcessor = ImageProcessor(imageRGBA: RGBAImage(image: self.image!)!) + } + filteredImage = imageProcessor?.applyFilter("redFilter").toUIImage() + showFilteredImage(filteredImage: filteredImage!) + + sender.isSelected = true + } + } + + @IBAction func onBlueFilter(_ sender: UIButton) { + enableCompareButton() + if(sender.isSelected) { + imageView.image = image + sender.isSelected = false + } else { + if (filteredImage != nil) { + imageProcessor = ImageProcessor(imageRGBA: RGBAImage(image: self.filteredImage!)!) + } else { + imageProcessor = ImageProcessor(imageRGBA: RGBAImage(image: self.image!)!) + } + filteredImage = imageProcessor?.applyFilter("blueFilter").toUIImage() + showFilteredImage(filteredImage: filteredImage!) + + sender.isSelected = true + } + } + + @IBAction func onGreenFilter(_ sender: UIButton) { + enableCompareButton() + if(sender.isSelected) { + imageView.image = image + sender.isSelected = false + } else { + if (filteredImage != nil) { + imageProcessor = ImageProcessor(imageRGBA: RGBAImage(image: self.filteredImage!)!) + } else { + imageProcessor = ImageProcessor(imageRGBA: RGBAImage(image: self.image!)!) + } + filteredImage = imageProcessor?.applyFilter("greenFilter").toUIImage() + showFilteredImage(filteredImage: filteredImage!) + + sender.isSelected = true + } + } + + @IBAction func onAlphaFilter(_ sender: UIButton) { + enableCompareButton() + if(sender.isSelected) { + imageView.image = image + sender.isSelected = false + } else { + if (filteredImage != nil) { + imageProcessor = ImageProcessor(imageRGBA: RGBAImage(image: self.filteredImage!)!) + } else { + imageProcessor = ImageProcessor(imageRGBA: RGBAImage(image: self.image!)!) + } + filteredImage = imageProcessor?.applyFilter("alphaFilter").toUIImage() + showFilteredImage(filteredImage: filteredImage!) + + sender.isSelected = true + } + } + + @IBAction func onShare(_ sender: Any) { + let activityController = UIActivityViewController(activityItems: [imageView.image!], applicationActivities: nil) + present(activityController, animated: true, completion: nil) + + } + + @IBAction func onNewPhoto(_ sender: Any) { + let actionSheet = UIAlertController(title: "New Photo", message: nil, preferredStyle: .actionSheet) + actionSheet.addAction(UIAlertAction(title: "Camera", style: .default, handler: { action in + self.showCamera() + })) + + actionSheet.addAction(UIAlertAction(title: "Album", style: .default, handler: { action + in + self.showAlbum() + })) + + actionSheet.addAction(UIAlertAction(title: "Cancel", style: .cancel, handler: nil)) + + self.present(actionSheet, animated: true, completion: nil) + } + + func showFilteredImage(filteredImage: UIImage) { + imageView.alpha = 1 + filteredImageView.alpha = 0 + + filteredImageView.image = filteredImage + + UIView.animate(withDuration: 0.4) { + self.filteredImageView.alpha = 1.0 + self.imageView.alpha = 0 + } + } + + func showOriginalImage() { + imageView.alpha = 0 + filteredImageView.alpha = 1 + + filteredImageView.image = filteredImage + + UIView.animate(withDuration: 0.4) { + self.filteredImageView.alpha = 0 + self.imageView.alpha = 1 + } + } + + func enableCompareButton() { + if compareButton.isEnabled == false { + compareButton.isEnabled = true + } + } + + func showCamera() { + let cameraPicker = UIImagePickerController() + cameraPicker.delegate = self + cameraPicker.sourceType = .camera + + present(cameraPicker, animated: true, completion: nil) + } + + func showAlbum() { + let cameraPicker = UIImagePickerController() + cameraPicker.delegate = self + cameraPicker.sourceType = .photoLibrary + + present(cameraPicker, animated: true, completion: nil) + } + + func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) { + dismiss(animated: true, completion: nil) + if let image = info[UIImagePickerControllerOriginalImage] as? UIImage{ + imageView.image = image + self.image = image + } + } + + func imagePickerControllerDidCancel(_ picker: UIImagePickerController) { + dismiss(animated: true, completion: nil) + } + + @IBAction func onFilter(_ sender: UIButton) { + if(sender.isSelected) { + hideSecondaryMenu() + sender.isSelected = false + } else { + showSecondaryMenu() + sender.isSelected = true + } + } + + func showSecondaryMenu() { + view.addSubview(secondaryMenu) + + let bottomConstraint = secondaryMenu.bottomAnchor.constraint(equalTo: bottomMenu.topAnchor) + let leftConstraint = secondaryMenu.leftAnchor.constraint(equalTo: view.leftAnchor) + let rightConstraint = secondaryMenu.rightAnchor.constraint(equalTo: view.rightAnchor) + + let heightConstraint = secondaryMenu.heightAnchor.constraint(equalToConstant: 44) + + NSLayoutConstraint.activate([bottomConstraint, leftConstraint, rightConstraint, heightConstraint]) + + view.layoutIfNeeded() + + self.secondaryMenu.alpha = 0 + UIView.animate(withDuration: 0.4) { + self.secondaryMenu.alpha = 1.0 + } + + } + + func hideSecondaryMenu() { + UIView.animate(withDuration: 0.4, animations: { + self.secondaryMenu.alpha = 0 + }, completion: { completed in + if completed == true { + self.secondaryMenu.removeFromSuperview() + } + }) + } + + func showOverlayOriginalImage() { + view.addSubview(originalOverlay) + + let topConstraint = originalOverlay.topAnchor.constraint(equalTo: view.topAnchor) + let leftConstraint = originalOverlay.leftAnchor.constraint(equalTo: view.leftAnchor) + let rightConstraint = originalOverlay.rightAnchor.constraint(equalTo: view.rightAnchor) + + let heightConstraint = originalOverlay.heightAnchor.constraint(equalToConstant: 44) + + NSLayoutConstraint.activate([topConstraint, leftConstraint, rightConstraint, heightConstraint]) + + view.layoutIfNeeded() + + showOriginalImage() + } + + func hideOverlayOriginalImage() { + self.originalOverlay.removeFromSuperview() + if (filteredImage != nil) { + showFilteredImage(filteredImage: filteredImage!) + } + } }