├── 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 |
--------------------------------------------------------------------------------