Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improves the security in ImagePicker #32

Merged
merged 11 commits into from
Sep 23, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions Demo/ImagePickerDemo/ImagePickerDemo.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -357,7 +357,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 8.4;
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
Expand Down Expand Up @@ -396,7 +396,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 8.4;
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
TARGETED_DEVICE_FAMILY = "1,2";
Expand Down Expand Up @@ -474,7 +474,7 @@
29D699F71B70ABFC0021FA73 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
defaultConfigurationName = Debug;
};
29D699F81B70ABFC0021FA73 /* Build configuration list for PBXNativeTarget "ImagePickerDemo" */ = {
isa = XCConfigurationList;
Expand All @@ -483,7 +483,7 @@
29D699FA1B70ABFC0021FA73 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
defaultConfigurationName = Debug;
};
29D699FB1B70ABFC0021FA73 /* Build configuration list for PBXNativeTarget "ImagePickerDemoTests" */ = {
isa = XCConfigurationList;
Expand All @@ -492,7 +492,7 @@
29D699FD1B70ABFC0021FA73 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
defaultConfigurationName = Debug;
};
/* End XCConfigurationList section */
};
Expand Down
12 changes: 8 additions & 4 deletions Demo/ImagePickerDemo/ImagePickerDemo/Base.lproj/LaunchScreen.xib
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="6214" systemVersion="14A314h" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES">
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="8191" systemVersion="15A282b" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES">
<dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="6207"/>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="8154"/>
<capability name="Constraints with non-1.0 multipliers" minToolsVersion="5.1"/>
</dependencies>
<objects>
Expand All @@ -13,17 +14,20 @@
<subviews>
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text=" Copyright (c) 2015 Ramon Gilabert Llop. All rights reserved." textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" minimumFontSize="9" translatesAutoresizingMaskIntoConstraints="NO" id="8ie-xW-0ye">
<rect key="frame" x="20" y="439" width="441" height="21"/>
<animations/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<color key="textColor" cocoaTouchSystemColor="darkTextColor"/>
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="ImagePickerDemo" textAlignment="center" lineBreakMode="middleTruncation" baselineAdjustment="alignBaselines" minimumFontSize="18" translatesAutoresizingMaskIntoConstraints="NO" id="kId-c2-rCX">
<rect key="frame" x="20" y="140" width="441" height="43"/>
<animations/>
<fontDescription key="fontDescription" type="boldSystem" pointSize="36"/>
<color key="textColor" cocoaTouchSystemColor="darkTextColor"/>
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/>
<nil key="highlightedColor"/>
</label>
</subviews>
<animations/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
<constraints>
<constraint firstItem="kId-c2-rCX" firstAttribute="centerY" secondItem="iN0-l3-epB" secondAttribute="bottom" multiplier="1/3" constant="1" id="5cJ-9S-tgC"/>
Expand Down
4 changes: 2 additions & 2 deletions Demo/ImagePickerDemo/ImagePickerDemo/Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,11 @@
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<string>no.ImagePicker.hyper</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<string>ImagePicker</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
Expand Down
4 changes: 2 additions & 2 deletions Demo/ImagePickerDemo/Podfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@ DEPENDENCIES:

EXTERNAL SOURCES:
ImagePicker:
:path: "../../"
:path: ../../

SPEC CHECKSUMS:
ImagePicker: 32becfa25b8e9179e60c45411b577340d35e3e32

COCOAPODS: 0.38.2
COCOAPODS: 0.39.0.beta.4
Binary file removed Images/flashIconOff.png
Binary file not shown.
Binary file removed Images/[email protected]
Binary file not shown.
Binary file removed Images/[email protected]
Binary file not shown.
4 changes: 2 additions & 2 deletions Source/BottomView/BottomContainerView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ class BottomContainerView: UIView {
lazy var doneButton: UIButton = { [unowned self] in
let button = UIButton()
button.setTitle(self.configuration.cancelButtonTitle, forState: .Normal)
button.titleLabel!.font = self.configuration.doneButton
button.titleLabel?.font = self.configuration.doneButton
button.addTarget(self, action: "doneButtonDidPress:", forControlEvents: .TouchUpInside)

return button
Expand Down Expand Up @@ -80,7 +80,7 @@ class BottomContainerView: UIView {
}

required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
fatalError("init(coder:) has not been implemented")
}

// MARK: - Action methods
Expand Down
5 changes: 2 additions & 3 deletions Source/BottomView/StackView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -109,14 +109,13 @@ extension ImageStackView {
}

func renderViews(images: [UIImage]) {
if images.count < 1 {
//TODO: subclass view and use setimage method here to automatically adjust alpha and NIL
if let firstView = views.first where images.count < 1 {
for imageView in views {
imageView.image = nil
imageView.alpha = 0
}

views.first!.alpha = 1
firstView.alpha = 1
return
}

Expand Down
86 changes: 49 additions & 37 deletions Source/CameraView/CameraView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -77,19 +77,20 @@ class CameraView: UIViewController {
let authorizationStatus = AVCaptureDevice.authorizationStatusForMediaType(AVMediaTypeVideo)

for device in devices {
if device.hasMediaType(AVMediaTypeVideo)
&& authorizationStatus == .Authorized {
captureDevice = device as? AVCaptureDevice
capturedDevices?.addObject(device as! AVCaptureDevice)
} else if device.hasMediaType(AVMediaTypeVideo)
&& authorizationStatus == .NotDetermined {
if let device = device as? AVCaptureDevice {
if device.hasMediaType(AVMediaTypeVideo) && authorizationStatus == .Authorized {
captureDevice = device
capturedDevices?.addObject(device)
} else if device.hasMediaType(AVMediaTypeVideo) && authorizationStatus == .NotDetermined {
AVCaptureDevice.requestAccessForMediaType(AVMediaTypeVideo,
completionHandler: { (granted: Bool) -> Void in
if granted {
self.captureDevice = device as? AVCaptureDevice
self.capturedDevices?.addObject(device as! AVCaptureDevice)
self.captureDevice = device
self.capturedDevices?.addObject(device)
}
})
}

}
}

Expand All @@ -103,7 +104,8 @@ class CameraView: UIViewController {
// MARK: - Camera actions

func rotateCamera() {
let deviceIndex = capturedDevices?.indexOfObject(captureDevice!)
guard let captureDevice = captureDevice else { return }
let deviceIndex = capturedDevices?.indexOfObject(captureDevice)
let currentDeviceInput = captureSession.inputs.first as! AVCaptureDeviceInput
var newDeviceIndex = 0

Expand All @@ -117,18 +119,19 @@ class CameraView: UIViewController {
}
}

captureDevice = capturedDevices?.objectAtIndex(newDeviceIndex) as? AVCaptureDevice
self.captureDevice = capturedDevices?.objectAtIndex(newDeviceIndex) as? AVCaptureDevice
configureDevice()

delegate?.handleFlashButton(captureDevice?.position == .Front)
delegate?.handleFlashButton(captureDevice.position == .Front)

guard let currentCaptureDevice = self.captureDevice else { return }
UIView.animateWithDuration(0.3, animations: { [unowned self] in
self.containerView.alpha = 1
}, completion: { finished in
self.captureSession.beginConfiguration()
self.captureSession.removeInput(currentDeviceInput)

if self.captureDevice!.supportsAVCaptureSessionPreset(AVCaptureSessionPreset1280x720) {
if currentCaptureDevice.supportsAVCaptureSessionPreset(AVCaptureSessionPreset1280x720) {
self.captureSession.sessionPreset = AVCaptureSessionPreset1280x720
} else {
self.captureSession.sessionPreset = AVCaptureSessionPreset640x480
Expand Down Expand Up @@ -173,29 +176,36 @@ class CameraView: UIViewController {
})

let queue = dispatch_queue_create("session queue", DISPATCH_QUEUE_SERIAL)
let videoOrientation = previewLayer?.connection.videoOrientation

stillImageOutput?.connectionWithMediaType(AVMediaTypeVideo).videoOrientation = videoOrientation!
if let videoOrientation = previewLayer?.connection.videoOrientation {
stillImageOutput?.connectionWithMediaType(AVMediaTypeVideo).videoOrientation = videoOrientation
}

guard let stillImageOutput = self.stillImageOutput else { return }

dispatch_async(queue, { [unowned self] in
self.stillImageOutput!.captureStillImageAsynchronouslyFromConnection(self.stillImageOutput!.connectionWithMediaType(AVMediaTypeVideo), completionHandler: { (buffer, error) -> Void in
let imageData = AVCaptureStillImageOutput.jpegStillImageNSDataRepresentation(buffer)
let image = self.cropImage(UIImage(data: imageData)!)
let orientation = self.pictureOrientation()
let assetsLibrary = ALAssetsLibrary()
assetsLibrary.writeImageToSavedPhotosAlbum(image.CGImage, orientation: orientation, completionBlock: nil)

let rotatedImage = UIImage(CGImage: image.CGImage!,
scale: 1.0,
orientation: UIImageOrientation(rawValue: orientation.rawValue)!)
self.delegate?.imageToLibrary(rotatedImage)
stillImageOutput.captureStillImageAsynchronouslyFromConnection(stillImageOutput.connectionWithMediaType(AVMediaTypeVideo),
completionHandler: { (buffer, error) -> Void in
let imageData = AVCaptureStillImageOutput.jpegStillImageNSDataRepresentation(buffer)
guard let imageFromData = UIImage(data: imageData) else { return }
let image = self.cropImage(imageFromData)
let orientation = self.pictureOrientation()
let assetsLibrary = ALAssetsLibrary()
assetsLibrary.writeImageToSavedPhotosAlbum(image.CGImage, orientation: orientation, completionBlock: nil)

guard let imageCG = image.CGImage, realOrientation = UIImageOrientation(rawValue: orientation.rawValue) else { return }
let rotatedImage = UIImage(CGImage: imageCG,
scale: 1.0,
orientation: realOrientation)
self.delegate?.imageToLibrary(rotatedImage)
})
})
})
}

func cropImage(image: UIImage) -> UIImage {
let imageReference = CGImageCreateWithImageInRect(image.CGImage, CGRect(x: 0, y: 0, width: image.size.height - 200, height: image.size.width))
let normalizedImage = UIImage(CGImage: imageReference!, scale: 1, orientation: .Right)
guard let imageReference = CGImageCreateWithImageInRect(image.CGImage,
CGRect(x: 0, y: 0, width: image.size.height - 200, height: image.size.width)) else { return UIImage() }
let normalizedImage = UIImage(CGImage: imageReference, scale: 1, orientation: .Right)

return normalizedImage
}
Expand Down Expand Up @@ -245,7 +255,8 @@ class CameraView: UIViewController {
}

override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
let anyTouch = touches.first!
guard let firstTouch = touches.first else { return }
let anyTouch = firstTouch
let touchX = anyTouch.locationInView(view).x
let touchY = anyTouch.locationInView(view).y
focusImageView.transform = CGAffineTransformIdentity
Expand Down Expand Up @@ -274,13 +285,13 @@ class CameraView: UIViewController {
print("failed to capture device")
}


previewLayer = AVCaptureVideoPreviewLayer(session: captureSession)
previewLayer?.autoreverses = true
previewLayer?.videoGravity = AVLayerVideoGravityResizeAspectFill
guard let previewLayer = AVCaptureVideoPreviewLayer(session: captureSession) else { return }
self.previewLayer = previewLayer
previewLayer.autoreverses = true
previewLayer.videoGravity = AVLayerVideoGravityResizeAspectFill
view.layer.addSublayer(previewLayer)
previewLayer.frame = view.layer.frame
view.clipsToBounds = true
view.layer.addSublayer(previewLayer!)
previewLayer?.frame = view.layer.frame
captureSession.startRunning()
delegate?.handleFlashButton(captureDevice?.position == .Front)
stillImageOutput = AVCaptureStillImageOutput()
Expand All @@ -295,8 +306,9 @@ class CameraView: UIViewController {
let bundlePath = NSBundle(forClass: self.classForCoder).resourcePath?.stringByAppendingString("/ImagePicker.bundle")
let bundle = NSBundle(path: bundlePath!)
let traitCollection = UITraitCollection(displayScale: 3)
let image = UIImage(named: name, inBundle: bundle, compatibleWithTraitCollection: traitCollection)

return image!
guard let image = UIImage(named: name, inBundle: bundle, compatibleWithTraitCollection: traitCollection) else { return UIImage() }

return image
}
}
24 changes: 12 additions & 12 deletions Source/Extensions/ConstraintsSetup.swift
Original file line number Diff line number Diff line change
Expand Up @@ -140,18 +140,18 @@ extension ImagePickerController {
extension ImageGalleryViewCell {

func setupConstraints() {
if !constraintsAdded {
for attribute: NSLayoutAttribute in [.Width, .Height, .CenterX, .CenterY] {
addConstraint(NSLayoutConstraint(item: imageView, attribute: attribute,
relatedBy: .Equal, toItem: self, attribute: attribute,
multiplier: 1, constant: 0))

addConstraint(NSLayoutConstraint(item: selectedImageView, attribute: attribute,
relatedBy: .Equal, toItem: self, attribute: attribute,
multiplier: 1, constant: 0))
}

constraintsAdded = true
guard !constraintsAdded else { return }

for attribute: NSLayoutAttribute in [.Width, .Height, .CenterX, .CenterY] {
addConstraint(NSLayoutConstraint(item: imageView, attribute: attribute,
relatedBy: .Equal, toItem: self, attribute: attribute,
multiplier: 1, constant: 0))

addConstraint(NSLayoutConstraint(item: selectedImageView, attribute: attribute,
relatedBy: .Equal, toItem: self, attribute: attribute,
multiplier: 1, constant: 0))
}

constraintsAdded = true
}
}
Loading