diff --git a/Example/CustomWaitingIndicator.swift b/Example/CustomWaitingIndicator.swift index 0acc4062..ab71ad9e 100644 --- a/Example/CustomWaitingIndicator.swift +++ b/Example/CustomWaitingIndicator.swift @@ -50,4 +50,3 @@ class CustomWaitingIndicator: UIView, Mantis.ActivityIndicatorProtocol { circleLayer.removeAnimation(forKey: "rotationAnimation") } } - diff --git a/Mantis.xcodeproj/project.pbxproj b/Mantis.xcodeproj/project.pbxproj index 31153553..aaae2671 100644 --- a/Mantis.xcodeproj/project.pbxproj +++ b/Mantis.xcodeproj/project.pbxproj @@ -634,7 +634,7 @@ ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "alias swiftlint=\"/opt/homebrew/bin/swiftlint\"\nif swiftlint >/dev/null; then\n swiftlint\nelse\n echo \"warning: SwiftLint not installed, download from https://github.com/realm/SwiftLint\"\nfi\n"; + shellScript = "export PATH=\"$PATH:/opt/homebrew/bin\"\nif which swiftlint >/dev/null; then\n swiftlint\nelse\n echo \"warning: SwiftLint not installed, download from https://github.com/realm/SwiftLint\"\nfi\n"; }; /* End PBXShellScriptBuildPhase section */ diff --git a/Sources/Mantis/CropView/CropAuxiliaryIndicatorView+Accessibility.swift b/Sources/Mantis/CropView/CropAuxiliaryIndicatorView+Accessibility.swift index bd1db92a..2f1f0777 100644 --- a/Sources/Mantis/CropView/CropAuxiliaryIndicatorView+Accessibility.swift +++ b/Sources/Mantis/CropView/CropAuxiliaryIndicatorView+Accessibility.swift @@ -52,7 +52,8 @@ extension CropAuxiliaryIndicatorView { break } - helperView.accessibilityHint = LocalizedHelper.getString("Mantis.Double tap and hold to adjust crop area", value: "Double tap and hold to adjust crop area") + helperView.accessibilityHint = LocalizedHelper.getString("Mantis.Double tap and hold to adjust crop area", + value: "Double tap and hold to adjust crop area") } } @@ -68,21 +69,45 @@ extension CropAuxiliaryIndicatorView { switch handleType { case .topLeft: - helperView.frame = CGRect(x: -cropBoxHotAreaUnit/2, y: -cropBoxHotAreaUnit/2, width: cropBoxHotAreaUnit, height: cropBoxHotAreaUnit) + helperView.frame = CGRect(x: -cropBoxHotAreaUnit/2, + y: -cropBoxHotAreaUnit/2, + width: cropBoxHotAreaUnit, + height: cropBoxHotAreaUnit) case .top: - helperView.frame = CGRect(x: cropBoxHotAreaUnit/2, y: -cropBoxHotAreaUnit/2, width: bounds.width - cropBoxHotAreaUnit, height: cropBoxHotAreaUnit) + helperView.frame = CGRect(x: cropBoxHotAreaUnit/2, + y: -cropBoxHotAreaUnit/2, + width: bounds.width - cropBoxHotAreaUnit, + height: cropBoxHotAreaUnit) case .topRight: - helperView.frame = CGRect(x: bounds.width - cropBoxHotAreaUnit/2, y: -cropBoxHotAreaUnit/2, width: cropBoxHotAreaUnit, height: cropBoxHotAreaUnit) + helperView.frame = CGRect(x: bounds.width - cropBoxHotAreaUnit/2, + y: -cropBoxHotAreaUnit/2, + width: cropBoxHotAreaUnit, + height: cropBoxHotAreaUnit) case .right: - helperView.frame = CGRect(x: bounds.width - cropBoxHotAreaUnit/2, y: cropBoxHotAreaUnit/2, width: cropBoxHotAreaUnit, height: bounds.height - cropBoxHotAreaUnit) + helperView.frame = CGRect(x: bounds.width - cropBoxHotAreaUnit/2, + y: cropBoxHotAreaUnit/2, + width: cropBoxHotAreaUnit, + height: bounds.height - cropBoxHotAreaUnit) case .bottomRight: - helperView.frame = CGRect(x: bounds.width - cropBoxHotAreaUnit/2, y: bounds.height - cropBoxHotAreaUnit/2, width: cropBoxHotAreaUnit, height: cropBoxHotAreaUnit) + helperView.frame = CGRect(x: bounds.width - cropBoxHotAreaUnit/2, + y: bounds.height - cropBoxHotAreaUnit/2, + width: cropBoxHotAreaUnit, + height: cropBoxHotAreaUnit) case .bottom: - helperView.frame = CGRect(x: cropBoxHotAreaUnit/2, y: bounds.height - cropBoxHotAreaUnit/2, width: bounds.width - cropBoxHotAreaUnit, height: cropBoxHotAreaUnit) + helperView.frame = CGRect(x: cropBoxHotAreaUnit/2, + y: bounds.height - cropBoxHotAreaUnit/2, + width: bounds.width - cropBoxHotAreaUnit, + height: cropBoxHotAreaUnit) case .bottomLeft: - helperView.frame = CGRect(x: -cropBoxHotAreaUnit/2, y: bounds.height - cropBoxHotAreaUnit/2, width: cropBoxHotAreaUnit, height: cropBoxHotAreaUnit) + helperView.frame = CGRect(x: -cropBoxHotAreaUnit/2, + y: bounds.height - cropBoxHotAreaUnit/2, + width: cropBoxHotAreaUnit, + height: cropBoxHotAreaUnit) case .left: - helperView.frame = CGRect(x: -cropBoxHotAreaUnit/2, y: cropBoxHotAreaUnit/2, width: cropBoxHotAreaUnit, height: bounds.height - cropBoxHotAreaUnit) + helperView.frame = CGRect(x: -cropBoxHotAreaUnit/2, + y: cropBoxHotAreaUnit/2, + width: cropBoxHotAreaUnit, + height: bounds.height - cropBoxHotAreaUnit) case .none: break } diff --git a/Sources/Mantis/CropViewController/CropToolbar.swift b/Sources/Mantis/CropViewController/CropToolbar.swift index fdfa0364..9c276315 100644 --- a/Sources/Mantis/CropViewController/CropToolbar.swift +++ b/Sources/Mantis/CropViewController/CropToolbar.swift @@ -281,7 +281,6 @@ extension CropToolbar { button.setContentCompressionResistancePriority(UILayoutPriority(rawValue: compressionPriority), for: .horizontal) button.setContentCompressionResistancePriority(UILayoutPriority(rawValue: compressionPriority), for: .vertical) - button.addTarget(self, action: action, for: .touchUpInside) button.contentEdgeInsets = UIEdgeInsets(top: 4, left: 10, bottom: 4, right: 10) diff --git a/Sources/Mantis/Extensions/CGImageExtensions.swift b/Sources/Mantis/Extensions/CGImageExtensions.swift index b163a6b5..ad5fa3ad 100644 --- a/Sources/Mantis/Extensions/CGImageExtensions.swift +++ b/Sources/Mantis/Extensions/CGImageExtensions.swift @@ -11,13 +11,18 @@ import UIKit +enum ImageProcessError: Error { + case noColorSpace + case failedToBuildContext(colorSpaceModel: CGColorSpaceModel, bitsPerPixel: Int, bitsPerComponent: Int) +} + extension CGImage { func transformedImage(_ transform: CGAffineTransform, outputSize: CGSize, cropSize: CGSize, - imageViewSize: CGSize) -> CGImage? { + imageViewSize: CGSize) throws -> CGImage? { guard var colorSpaceRef = self.colorSpace else { - return self + throw ImageProcessError.noColorSpace } // If the color space does not allow output, default to the RGB color space @@ -32,16 +37,18 @@ extension CGImage { switch(bitsPerPixel, bitsPerComponent) { case (16, 5): return CGImageAlphaInfo.noneSkipFirst.rawValue - case (24, 8), (32, 8), (48, 16), (64, 16): + case (24, 8), (48, 16): + return CGImageAlphaInfo.none.rawValue + case (32, 8), (64, 16): return CGImageAlphaInfo.premultipliedLast.rawValue case (32, 10): if #available(iOS 12, macOS 10.14, *) { return CGImageAlphaInfo.alphaOnly.rawValue | CGImagePixelFormatInfo.RGBCIF10.rawValue } else { - return bitmapInfo.rawValue + break } case (128, 32): - return CGImageAlphaInfo.premultipliedLast.rawValue | CGBitmapInfo.floatComponents.rawValue + return CGImageAlphaInfo.premultipliedLast.rawValue | (bitmapInfo.rawValue & CGBitmapInfo.floatComponents.rawValue) default: break } @@ -57,7 +64,9 @@ extension CGImage { bytesPerRow: bitmapBytesPerRow, space: colorSpaceRef, bitmapInfo: getBitmapInfo()) else { - return self + throw ImageProcessError.failedToBuildContext(colorSpaceModel: colorSpaceRef.model, + bitsPerPixel: bitsPerPixel, + bitsPerComponent: bitsPerComponent) } context.setFillColor(UIColor.clear.cgColor) diff --git a/Sources/Mantis/Extensions/UIImageExtensions.swift b/Sources/Mantis/Extensions/UIImageExtensions.swift index 018bfe60..6da15510 100644 --- a/Sources/Mantis/Extensions/UIImageExtensions.swift +++ b/Sources/Mantis/Extensions/UIImageExtensions.swift @@ -100,14 +100,25 @@ extension UIImage { transform.transformed(by: cropInfo) let outputSize = getOutputCropImageSize(by: cropInfo) - guard let transformedCGImage = fixedOrientationImage.transformedImage(transform, - outputSize: outputSize, - cropSize: cropInfo.cropSize, - imageViewSize: cropInfo.imageViewSize) else { + + do { + guard let transformedCGImage = try fixedOrientationImage.transformedImage(transform, + outputSize: outputSize, + cropSize: cropInfo.cropSize, + imageViewSize: cropInfo.imageViewSize) else { + return nil + } + + return UIImage(cgImage: transformedCGImage) + } catch { + print("*** Failed to get transfromed image ***") + + if let error = error as? ImageProcessError { + print("Failed reason: \(error)") + } + return nil } - - return UIImage(cgImage: transformedCGImage) } func getOutputCropImageSize(by cropInfo: CropInfo) -> CGSize { diff --git a/Sources/Mantis/Protocols/RotationDialProtocol.swift b/Sources/Mantis/Protocols/RotationDialProtocol.swift index 4947244f..96a4a90e 100644 --- a/Sources/Mantis/Protocols/RotationDialProtocol.swift +++ b/Sources/Mantis/Protocols/RotationDialProtocol.swift @@ -17,7 +17,6 @@ protocol RotationDialProtocol: UIView { func setup(with frame: CGRect) @discardableResult func rotateDialPlate(by angle: Angle) -> Bool func rotateDialPlate(to angle: Angle, animated: Bool) - func resetAngle(animated: Bool) func getRotationAngle() -> Angle func setRotationCenter(by point: CGPoint, of view: UIView) func reset() diff --git a/Sources/Mantis/RotationDial/RotationDial.swift b/Sources/Mantis/RotationDial/RotationDial.swift index e0786f2a..7ef87051 100644 --- a/Sources/Mantis/RotationDial/RotationDial.swift +++ b/Sources/Mantis/RotationDial/RotationDial.swift @@ -259,10 +259,6 @@ extension RotationDial: RotationDialProtocol { } } - func resetAngle(animated: Bool) { - rotateDialPlate(to: Angle(radians: 0), animated: animated) - } - func getRotationAngle() -> Angle { guard let dialPlate = dialPlate else { return Angle(degrees: 0) } diff --git a/Sources/Mantis/RotationDial/RotationDialPlate.swift b/Sources/Mantis/RotationDial/RotationDialPlate.swift index 09cf5a72..e37cb5f2 100644 --- a/Sources/Mantis/RotationDial/RotationDialPlate.swift +++ b/Sources/Mantis/RotationDial/RotationDialPlate.swift @@ -145,7 +145,7 @@ class RotationDialPlate: UIView { private func setCenterPart() { let layer = CAShapeLayer() let radius: CGFloat = 4 - layer.frame = CGRect(x: (self.layer.bounds.width - radius) / 2 , + layer.frame = CGRect(x: (self.layer.bounds.width - radius) / 2, y: (self.layer.bounds.height - radius) / 2, width: radius, height: radius) diff --git a/SwiftUIExample/MantisSwiftUIExample/CameraView.swift b/SwiftUIExample/MantisSwiftUIExample/CameraView.swift index 003c5acb..ed0a4f3f 100644 --- a/SwiftUIExample/MantisSwiftUIExample/CameraView.swift +++ b/SwiftUIExample/MantisSwiftUIExample/CameraView.swift @@ -31,7 +31,7 @@ struct CameraView: UIViewControllerRepresentable { _image = image } - func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) { + func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey: Any]) { if let selectedImage = info[.originalImage] as? UIImage { self.image = selectedImage } @@ -43,4 +43,3 @@ struct CameraView: UIViewControllerRepresentable { } } } - diff --git a/SwiftUIExample/MantisSwiftUIExample/CustomViewController.swift b/SwiftUIExample/MantisSwiftUIExample/CustomViewController.swift index 3cba1c3b..e7e464aa 100644 --- a/SwiftUIExample/MantisSwiftUIExample/CustomViewController.swift +++ b/SwiftUIExample/MantisSwiftUIExample/CustomViewController.swift @@ -41,4 +41,3 @@ class CustomViewController: Mantis.CropViewController { crop() } } - diff --git a/SwiftUIExample/MantisSwiftUIExample/ImagePickerView.swift b/SwiftUIExample/MantisSwiftUIExample/ImagePickerView.swift index 3c269fe8..e8db119f 100644 --- a/SwiftUIExample/MantisSwiftUIExample/ImagePickerView.swift +++ b/SwiftUIExample/MantisSwiftUIExample/ImagePickerView.swift @@ -19,7 +19,7 @@ struct ImagePickerView: UIViewControllerRepresentable { self.parent = parent } - func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) { + func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey: Any]) { if let selectedImage = info[.originalImage] as? UIImage { parent.image = selectedImage } diff --git a/SwiftUIExample/MantisSwiftUIExample/SourceTypeSelectionView.swift b/SwiftUIExample/MantisSwiftUIExample/SourceTypeSelectionView.swift index be57cdd1..daf82599 100644 --- a/SwiftUIExample/MantisSwiftUIExample/SourceTypeSelectionView.swift +++ b/SwiftUIExample/MantisSwiftUIExample/SourceTypeSelectionView.swift @@ -41,7 +41,6 @@ struct SourceTypeSelectionView: View { } } - struct SourceTypeSelectionView_Previews: PreviewProvider { static var previews: some View { SourceTypeSelectionView(showSourceTypeSelection: .constant(false), showCamera: .constant(false), showImagePicker: .constant(false)) diff --git a/Tests/MantisTests/CropWorkbenchViewTests.swift b/Tests/MantisTests/CropWorkbenchViewTests.swift index 92164a41..ea74a873 100644 --- a/Tests/MantisTests/CropWorkbenchViewTests.swift +++ b/Tests/MantisTests/CropWorkbenchViewTests.swift @@ -21,20 +21,26 @@ final class CropWorkbenchViewTests: XCTestCase { } func testUpdateMinZoomScale() { - workbechView = CropWorkbenchView(frame: .zero, minimumZoomScale: 1.0, maximumZoomScale: 15, imageContainer: FakeImageContainer(frame: .init(x: 0, y: 0, width: 200, height: 100))) + let fakeImageContainer = FakeImageContainer(frame: .init(x: 0, y: 0, width: 200, height: 100)) + workbechView = CropWorkbenchView(frame: .zero, + minimumZoomScale: 1.0, + maximumZoomScale: 15, + imageContainer: fakeImageContainer) workbechView.bounds = CGRect(x: 0, y: 0, width: 400, height: 100) workbechView.updateMinZoomScale() XCTAssertEqual(workbechView.minimumZoomScale, 2) - workbechView = CropWorkbenchView(frame: .zero, minimumZoomScale: 1.0, maximumZoomScale: 15, imageContainer: FakeImageContainer(frame: .init(x: 0, y: 0, width: 200, height: 100))) + workbechView = CropWorkbenchView(frame: .zero, + minimumZoomScale: 1.0, + maximumZoomScale: 15, + imageContainer: fakeImageContainer) workbechView.bounds = CGRect(x: 0, y: 0, width: 400, height: 300) workbechView.updateMinZoomScale() XCTAssertEqual(workbechView.minimumZoomScale, 3) } - func testShouldScale() { workbechView.bounds = CGRect(x: 0, y: 0, width: 200, height: 100) workbechView.contentSize = CGSize(width: 200, height: 100) diff --git a/Tests/MantisTests/Mock/FakeRotationDialView.swift b/Tests/MantisTests/Mock/FakeRotationDialView.swift index a77faf46..58fb038f 100644 --- a/Tests/MantisTests/Mock/FakeRotationDialView.swift +++ b/Tests/MantisTests/Mock/FakeRotationDialView.swift @@ -31,10 +31,6 @@ class FakeRotationDialView: UIView, RotationDialProtocol { } - func resetAngle(animated: Bool) { - - } - func getRotationAngle() -> Angle { .init(degrees: 0) }