├── Images.xcodeproj ├── .keep ├── project.xcworkspace │ └── contents.xcworkspacedata ├── xcuserdata │ └── ben.xcuserdatad │ │ └── xcschemes │ │ ├── xcschememanagement.plist │ │ └── Images.xcscheme └── project.pbxproj ├── .gitignore └── Images └── main.swift /Images.xcodeproj/.keep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Images.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | build/ 3 | *.pbxuser 4 | !default.pbxuser 5 | *.mode1v3 6 | !default.mode1v3 7 | *.mode2v3 8 | !default.mode2v3 9 | *.perspectivev3 10 | !default.perspectivev3 11 | *.xcworkspace 12 | !default.xcworkspace 13 | xcuserdata 14 | profile 15 | *.moved-aside 16 | DerivedData 17 | .idea/ 18 | Pod 19 | Pods 20 | UserInterfaceState.xcuserstate 21 | ip_address.txt -------------------------------------------------------------------------------- /Images.xcodeproj/xcuserdata/ben.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | Images.xcscheme 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | SuppressBuildableAutocreation 14 | 15 | B552C80D1BAE6A62006AD033 16 | 17 | primary 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /Images.xcodeproj/xcuserdata/ben.xcuserdatad/xcschemes/Images.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 39 | 40 | 41 | 42 | 43 | 44 | 54 | 56 | 62 | 63 | 64 | 65 | 66 | 67 | 73 | 75 | 81 | 82 | 83 | 84 | 86 | 87 | 90 | 91 | 92 | -------------------------------------------------------------------------------- /Images/main.swift: -------------------------------------------------------------------------------- 1 | import CoreImage 2 | import AppKit 3 | import AVFoundation 4 | import ImageIO 5 | 6 | func imageDimensionsFitInRatio(ratio: CGFloat, width: CGFloat, height: CGFloat) -> Bool { 7 | let imageRatio = height / width 8 | return imageRatio <= 1 && imageRatio >= ratio 9 | } 10 | 11 | func findCenterOfFeatures(features: [CIFeature], height: CGFloat) -> CGFloat { 12 | var center: CGFloat = 0 13 | if features.count > 0 { 14 | center = 0 15 | for feature in features where feature.type == "Face" { 16 | center += CGRectGetMidY(feature.bounds) 17 | } 18 | center = center / CGFloat(features.count) 19 | } 20 | return center 21 | } 22 | 23 | func cropRectangleOnCenter(center: CGFloat, width: CGFloat, height: CGFloat, ratio: CGFloat) -> CGRect { 24 | let cropHeight = floor(ratio * width) 25 | let halfCropHeight = cropHeight / 2 26 | 27 | var yPosition = center - halfCropHeight 28 | if center - halfCropHeight < 0 { 29 | yPosition = 0 30 | } else if center + halfCropHeight > height { 31 | yPosition = height - cropHeight 32 | } 33 | 34 | print("center: \(center)") 35 | print("halfCropHeight: \(halfCropHeight)") 36 | print("yPosition: \(yPosition)") 37 | 38 | return CGRect(x: 0, y: yPosition, width: width, height: cropHeight) 39 | } 40 | 41 | print(NSDate()) 42 | 43 | let paths = [ 44 | "/Users/ben/Desktop/jim_sharp.jpg", 45 | ] 46 | 47 | let outputDirectory = NSURL(fileURLWithPath: "/Users/ben/Desktop/output/", isDirectory: true) 48 | let ratio:CGFloat = 9/16 49 | 50 | for path in paths { 51 | let url = NSURL(fileURLWithPath: path) 52 | if let imageSource = CGImageSourceCreateWithURL(url, nil), dict = CGImageSourceCopyPropertiesAtIndex(imageSource, 0, nil) { 53 | let properties = dict as NSDictionary 54 | let widthProperty = kCGImagePropertyPixelWidth as String 55 | let heightProperty = kCGImagePropertyPixelHeight as String 56 | if let originalWidth = properties[widthProperty] as? CGFloat, originalHeight = properties[heightProperty] as? CGFloat where imageDimensionsFitInRatio(ratio, width: originalWidth, height: originalHeight) { 57 | let options: [NSObject:AnyObject] = [ 58 | kCGImageSourceShouldAllowFloat : true, 59 | kCGImageSourceCreateThumbnailWithTransform: true, 60 | kCGImageSourceCreateThumbnailFromImageAlways: true, 61 | kCGImageSourceThumbnailMaxPixelSize: Int(542) 62 | ] 63 | 64 | if let initialImage = CGImageSourceCreateThumbnailAtIndex(imageSource, 0, options) { 65 | let width = CGImageGetWidth(initialImage) 66 | let height = CGImageGetHeight(initialImage) 67 | let image = CIImage(CGImage: initialImage) 68 | let options: [String: AnyObject] = [CIDetectorAccuracy:CIDetectorAccuracyHigh] 69 | let detector = CIDetector(ofType:CIDetectorTypeFace, context:nil, options: options) 70 | let features = detector.featuresInImage(image) 71 | let center = findCenterOfFeatures(features, height: CGFloat(height)) 72 | 73 | let crop = cropRectangleOnCenter(center, width: CGFloat(width), height: CGFloat(height), ratio: ratio) 74 | let croppedImage = image.imageByCroppingToRect(crop) 75 | if let filter = CIFilter(name: "CIUnsharpMask", withInputParameters: ["inputImage": croppedImage, "inputRadius": 1.50, "inputIntensity": 0.50]), outputImage = filter.outputImage { 76 | let representation = NSBitmapImageRep(CIImage: outputImage) 77 | 78 | let fileProperties = [NSImageCompressionFactor: 0.6] 79 | if let data = representation.representationUsingType(NSBitmapImageFileType.NSJPEGFileType, properties: fileProperties), filename = url.lastPathComponent { 80 | let outputURL = outputDirectory.URLByAppendingPathComponent(filename) 81 | data.writeToURL(outputURL, atomically: true) 82 | } 83 | } 84 | 85 | } 86 | } 87 | } 88 | } 89 | 90 | print(NSDate()) 91 | 92 | -------------------------------------------------------------------------------- /Images.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | B552C8121BAE6A62006AD033 /* main.swift in Sources */ = {isa = PBXBuildFile; fileRef = B552C8111BAE6A62006AD033 /* main.swift */; }; 11 | /* End PBXBuildFile section */ 12 | 13 | /* Begin PBXCopyFilesBuildPhase section */ 14 | B552C80C1BAE6A62006AD033 /* CopyFiles */ = { 15 | isa = PBXCopyFilesBuildPhase; 16 | buildActionMask = 2147483647; 17 | dstPath = /usr/share/man/man1/; 18 | dstSubfolderSpec = 0; 19 | files = ( 20 | ); 21 | runOnlyForDeploymentPostprocessing = 1; 22 | }; 23 | /* End PBXCopyFilesBuildPhase section */ 24 | 25 | /* Begin PBXFileReference section */ 26 | B552C80E1BAE6A62006AD033 /* Images */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = Images; sourceTree = BUILT_PRODUCTS_DIR; }; 27 | B552C8111BAE6A62006AD033 /* main.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = main.swift; sourceTree = ""; }; 28 | /* End PBXFileReference section */ 29 | 30 | /* Begin PBXFrameworksBuildPhase section */ 31 | B552C80B1BAE6A62006AD033 /* Frameworks */ = { 32 | isa = PBXFrameworksBuildPhase; 33 | buildActionMask = 2147483647; 34 | files = ( 35 | ); 36 | runOnlyForDeploymentPostprocessing = 0; 37 | }; 38 | /* End PBXFrameworksBuildPhase section */ 39 | 40 | /* Begin PBXGroup section */ 41 | B552C8051BAE6A62006AD033 = { 42 | isa = PBXGroup; 43 | children = ( 44 | B552C8101BAE6A62006AD033 /* Images */, 45 | B552C80F1BAE6A62006AD033 /* Products */, 46 | ); 47 | sourceTree = ""; 48 | }; 49 | B552C80F1BAE6A62006AD033 /* Products */ = { 50 | isa = PBXGroup; 51 | children = ( 52 | B552C80E1BAE6A62006AD033 /* Images */, 53 | ); 54 | name = Products; 55 | sourceTree = ""; 56 | }; 57 | B552C8101BAE6A62006AD033 /* Images */ = { 58 | isa = PBXGroup; 59 | children = ( 60 | B552C8111BAE6A62006AD033 /* main.swift */, 61 | ); 62 | path = Images; 63 | sourceTree = ""; 64 | }; 65 | /* End PBXGroup section */ 66 | 67 | /* Begin PBXNativeTarget section */ 68 | B552C80D1BAE6A62006AD033 /* Images */ = { 69 | isa = PBXNativeTarget; 70 | buildConfigurationList = B552C8151BAE6A62006AD033 /* Build configuration list for PBXNativeTarget "Images" */; 71 | buildPhases = ( 72 | B552C80A1BAE6A62006AD033 /* Sources */, 73 | B552C80B1BAE6A62006AD033 /* Frameworks */, 74 | B552C80C1BAE6A62006AD033 /* CopyFiles */, 75 | ); 76 | buildRules = ( 77 | ); 78 | dependencies = ( 79 | ); 80 | name = Images; 81 | productName = Images; 82 | productReference = B552C80E1BAE6A62006AD033 /* Images */; 83 | productType = "com.apple.product-type.tool"; 84 | }; 85 | /* End PBXNativeTarget section */ 86 | 87 | /* Begin PBXProject section */ 88 | B552C8061BAE6A62006AD033 /* Project object */ = { 89 | isa = PBXProject; 90 | attributes = { 91 | LastUpgradeCheck = 0700; 92 | ORGANIZATIONNAME = "Feedbin, Inc."; 93 | TargetAttributes = { 94 | B552C80D1BAE6A62006AD033 = { 95 | CreatedOnToolsVersion = 7.0; 96 | }; 97 | }; 98 | }; 99 | buildConfigurationList = B552C8091BAE6A62006AD033 /* Build configuration list for PBXProject "Images" */; 100 | compatibilityVersion = "Xcode 3.2"; 101 | developmentRegion = English; 102 | hasScannedForEncodings = 0; 103 | knownRegions = ( 104 | en, 105 | ); 106 | mainGroup = B552C8051BAE6A62006AD033; 107 | productRefGroup = B552C80F1BAE6A62006AD033 /* Products */; 108 | projectDirPath = ""; 109 | projectRoot = ""; 110 | targets = ( 111 | B552C80D1BAE6A62006AD033 /* Images */, 112 | ); 113 | }; 114 | /* End PBXProject section */ 115 | 116 | /* Begin PBXSourcesBuildPhase section */ 117 | B552C80A1BAE6A62006AD033 /* Sources */ = { 118 | isa = PBXSourcesBuildPhase; 119 | buildActionMask = 2147483647; 120 | files = ( 121 | B552C8121BAE6A62006AD033 /* main.swift in Sources */, 122 | ); 123 | runOnlyForDeploymentPostprocessing = 0; 124 | }; 125 | /* End PBXSourcesBuildPhase section */ 126 | 127 | /* Begin XCBuildConfiguration section */ 128 | B552C8131BAE6A62006AD033 /* Debug */ = { 129 | isa = XCBuildConfiguration; 130 | buildSettings = { 131 | ALWAYS_SEARCH_USER_PATHS = NO; 132 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 133 | CLANG_CXX_LIBRARY = "libc++"; 134 | CLANG_ENABLE_MODULES = YES; 135 | CLANG_ENABLE_OBJC_ARC = YES; 136 | CLANG_WARN_BOOL_CONVERSION = YES; 137 | CLANG_WARN_CONSTANT_CONVERSION = YES; 138 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 139 | CLANG_WARN_EMPTY_BODY = YES; 140 | CLANG_WARN_ENUM_CONVERSION = YES; 141 | CLANG_WARN_INT_CONVERSION = YES; 142 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 143 | CLANG_WARN_UNREACHABLE_CODE = YES; 144 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 145 | COPY_PHASE_STRIP = NO; 146 | DEBUG_INFORMATION_FORMAT = dwarf; 147 | ENABLE_STRICT_OBJC_MSGSEND = YES; 148 | ENABLE_TESTABILITY = YES; 149 | GCC_C_LANGUAGE_STANDARD = gnu99; 150 | GCC_DYNAMIC_NO_PIC = NO; 151 | GCC_NO_COMMON_BLOCKS = YES; 152 | GCC_OPTIMIZATION_LEVEL = 0; 153 | GCC_PREPROCESSOR_DEFINITIONS = ( 154 | "DEBUG=1", 155 | "$(inherited)", 156 | ); 157 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 158 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 159 | GCC_WARN_UNDECLARED_SELECTOR = YES; 160 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 161 | GCC_WARN_UNUSED_FUNCTION = YES; 162 | GCC_WARN_UNUSED_VARIABLE = YES; 163 | MACOSX_DEPLOYMENT_TARGET = 10.11; 164 | MTL_ENABLE_DEBUG_INFO = YES; 165 | ONLY_ACTIVE_ARCH = YES; 166 | SDKROOT = macosx; 167 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 168 | }; 169 | name = Debug; 170 | }; 171 | B552C8141BAE6A62006AD033 /* Release */ = { 172 | isa = XCBuildConfiguration; 173 | buildSettings = { 174 | ALWAYS_SEARCH_USER_PATHS = NO; 175 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 176 | CLANG_CXX_LIBRARY = "libc++"; 177 | CLANG_ENABLE_MODULES = YES; 178 | CLANG_ENABLE_OBJC_ARC = YES; 179 | CLANG_WARN_BOOL_CONVERSION = YES; 180 | CLANG_WARN_CONSTANT_CONVERSION = YES; 181 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 182 | CLANG_WARN_EMPTY_BODY = YES; 183 | CLANG_WARN_ENUM_CONVERSION = YES; 184 | CLANG_WARN_INT_CONVERSION = YES; 185 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 186 | CLANG_WARN_UNREACHABLE_CODE = YES; 187 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 188 | COPY_PHASE_STRIP = NO; 189 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 190 | ENABLE_NS_ASSERTIONS = NO; 191 | ENABLE_STRICT_OBJC_MSGSEND = YES; 192 | GCC_C_LANGUAGE_STANDARD = gnu99; 193 | GCC_NO_COMMON_BLOCKS = YES; 194 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 195 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 196 | GCC_WARN_UNDECLARED_SELECTOR = YES; 197 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 198 | GCC_WARN_UNUSED_FUNCTION = YES; 199 | GCC_WARN_UNUSED_VARIABLE = YES; 200 | MACOSX_DEPLOYMENT_TARGET = 10.11; 201 | MTL_ENABLE_DEBUG_INFO = NO; 202 | SDKROOT = macosx; 203 | }; 204 | name = Release; 205 | }; 206 | B552C8161BAE6A62006AD033 /* Debug */ = { 207 | isa = XCBuildConfiguration; 208 | buildSettings = { 209 | PRODUCT_NAME = "$(TARGET_NAME)"; 210 | }; 211 | name = Debug; 212 | }; 213 | B552C8171BAE6A62006AD033 /* Release */ = { 214 | isa = XCBuildConfiguration; 215 | buildSettings = { 216 | PRODUCT_NAME = "$(TARGET_NAME)"; 217 | }; 218 | name = Release; 219 | }; 220 | /* End XCBuildConfiguration section */ 221 | 222 | /* Begin XCConfigurationList section */ 223 | B552C8091BAE6A62006AD033 /* Build configuration list for PBXProject "Images" */ = { 224 | isa = XCConfigurationList; 225 | buildConfigurations = ( 226 | B552C8131BAE6A62006AD033 /* Debug */, 227 | B552C8141BAE6A62006AD033 /* Release */, 228 | ); 229 | defaultConfigurationIsVisible = 0; 230 | defaultConfigurationName = Release; 231 | }; 232 | B552C8151BAE6A62006AD033 /* Build configuration list for PBXNativeTarget "Images" */ = { 233 | isa = XCConfigurationList; 234 | buildConfigurations = ( 235 | B552C8161BAE6A62006AD033 /* Debug */, 236 | B552C8171BAE6A62006AD033 /* Release */, 237 | ); 238 | defaultConfigurationIsVisible = 0; 239 | }; 240 | /* End XCConfigurationList section */ 241 | }; 242 | rootObject = B552C8061BAE6A62006AD033 /* Project object */; 243 | } 244 | --------------------------------------------------------------------------------