diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 20155a1..2525db9 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -12,7 +12,7 @@ jobs: - uses: actions/checkout@v4 - uses: ruby/setup-ruby@v1 with: - ruby-version: '2.7' + ruby-version: '3.2.2' bundler-cache: true - uses: actions/cache@v4 with: diff --git a/Example/Podfile.lock b/Example/Podfile.lock index 263df2a..658427f 100644 --- a/Example/Podfile.lock +++ b/Example/Podfile.lock @@ -31,4 +31,4 @@ SPEC CHECKSUMS: PODFILE CHECKSUM: e2296c0f63c75329f0583a4252b3dfcb582ff009 -COCOAPODS: 1.15.2 +COCOAPODS: 1.16.2 diff --git a/Example/RSKImageCropperExample.xcodeproj/project.pbxproj b/Example/RSKImageCropperExample.xcodeproj/project.pbxproj index b8501e4..8766d11 100644 --- a/Example/RSKImageCropperExample.xcodeproj/project.pbxproj +++ b/Example/RSKImageCropperExample.xcodeproj/project.pbxproj @@ -555,12 +555,12 @@ isa = XCBuildConfiguration; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CURRENT_PROJECT_VERSION = 6; + CURRENT_PROJECT_VERSION = 7; DEVELOPMENT_TEAM = J3P7YV7464; GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = "RSKImageCropperExample/RSKImageCropperExample-Prefix.pch"; INFOPLIST_FILE = "RSKImageCropperExample/RSKImageCropperExample-Info.plist"; - MARKETING_VERSION = 4.1.1; + MARKETING_VERSION = 5.0.0; PRODUCT_BUNDLE_IDENTIFIER = "com.ruslanskorb.${PRODUCT_NAME:rfc1034identifier}"; PRODUCT_NAME = RSKImageCropperExample; TARGETED_DEVICE_FAMILY = 1; @@ -572,12 +572,12 @@ isa = XCBuildConfiguration; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CURRENT_PROJECT_VERSION = 6; + CURRENT_PROJECT_VERSION = 7; DEVELOPMENT_TEAM = J3P7YV7464; GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = "RSKImageCropperExample/RSKImageCropperExample-Prefix.pch"; INFOPLIST_FILE = "RSKImageCropperExample/RSKImageCropperExample-Info.plist"; - MARKETING_VERSION = 4.1.1; + MARKETING_VERSION = 5.0.0; PRODUCT_BUNDLE_IDENTIFIER = "com.ruslanskorb.${PRODUCT_NAME:rfc1034identifier}"; PRODUCT_NAME = RSKImageCropperExample; TARGETED_DEVICE_FAMILY = 1; diff --git a/Gemfile b/Gemfile index 82e59d6..2f128c2 100644 --- a/Gemfile +++ b/Gemfile @@ -1,6 +1,6 @@ source 'https://rubygems.org' -gem 'cocoapods', '1.15.2' +gem 'cocoapods', '1.16.2' gem 'fui', '0.5.0' -gem 'xcpretty', '0.3.0' +gem 'xcpretty', '0.4.0' diff --git a/Gemfile.lock b/Gemfile.lock index c558644..a54516f 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -5,29 +5,32 @@ GEM base64 nkf rexml - activesupport (7.1.3.2) + activesupport (7.2.2) base64 + benchmark (>= 0.3) bigdecimal - concurrent-ruby (~> 1.0, >= 1.0.2) + concurrent-ruby (~> 1.0, >= 1.3.1) connection_pool (>= 2.2.5) drb i18n (>= 1.6, < 2) + logger (>= 1.4.2) minitest (>= 5.1) - mutex_m - tzinfo (~> 2.0) - addressable (2.8.6) - public_suffix (>= 2.0.2, < 6.0) + securerandom (>= 0.3) + tzinfo (~> 2.0, >= 2.0.5) + addressable (2.8.7) + public_suffix (>= 2.0.2, < 7.0) algoliasearch (1.27.5) httpclient (~> 2.8, >= 2.8.3) json (>= 1.5.1) atomos (0.1.3) base64 (0.2.0) - bigdecimal (3.1.7) + benchmark (0.4.0) + bigdecimal (3.1.8) claide (1.1.0) - cocoapods (1.15.2) + cocoapods (1.16.2) addressable (~> 2.8) claide (>= 1.0.2, < 2.0) - cocoapods-core (= 1.15.2) + cocoapods-core (= 1.16.2) cocoapods-deintegrate (>= 1.0.3, < 2.0) cocoapods-downloader (>= 2.1, < 3.0) cocoapods-plugins (>= 1.0.0, < 2.0) @@ -41,8 +44,8 @@ GEM molinillo (~> 0.8.0) nap (~> 1.0) ruby-macho (>= 2.3.0, < 3.0) - xcodeproj (>= 1.23.0, < 2.0) - cocoapods-core (1.15.2) + xcodeproj (>= 1.27.0, < 2.0) + cocoapods-core (1.16.2) activesupport (>= 5.0, < 8) addressable (~> 2.8) algoliasearch (~> 1.0) @@ -62,13 +65,13 @@ GEM netrc (~> 0.11) cocoapods-try (1.2.0) colored2 (3.1.2) - concurrent-ruby (1.2.3) + concurrent-ruby (1.3.4) connection_pool (2.4.1) drb (2.2.1) escape (0.0.4) ethon (0.16.0) ffi (>= 1.15.0) - ffi (1.16.3) + ffi (1.17.0) fourflusher (2.3.1) fui (0.5.0) gli @@ -76,41 +79,42 @@ GEM gh_inspector (1.1.3) gli (2.21.1) httpclient (2.8.3) - i18n (1.14.4) + i18n (1.14.6) concurrent-ruby (~> 1.0) - json (2.7.2) - minitest (5.22.3) + json (2.8.2) + logger (1.6.1) + minitest (5.25.2) molinillo (0.8.0) - mutex_m (0.2.0) - nanaimo (0.3.0) + nanaimo (0.4.0) nap (1.1.0) netrc (0.11.0) nkf (0.2.0) public_suffix (4.0.7) rexml (3.3.9) - rouge (2.0.7) + rouge (3.28.0) ruby-macho (2.5.1) + securerandom (0.3.2) typhoeus (1.4.1) ethon (>= 0.9.0) tzinfo (2.0.6) concurrent-ruby (~> 1.0) - xcodeproj (1.25.1) + xcodeproj (1.27.0) CFPropertyList (>= 2.3.3, < 4.0) atomos (~> 0.1.3) claide (>= 1.0.2, < 2.0) colored2 (~> 3.1) - nanaimo (~> 0.3.0) + nanaimo (~> 0.4.0) rexml (>= 3.3.6, < 4.0) - xcpretty (0.3.0) - rouge (~> 2.0.7) + xcpretty (0.4.0) + rouge (~> 3.28.0) PLATFORMS ruby DEPENDENCIES - cocoapods (= 1.15.2) + cocoapods (= 1.16.2) fui (= 0.5.0) - xcpretty (= 0.3.0) + xcpretty (= 0.4.0) BUNDLED WITH 2.4.10 diff --git a/RSKImageCropper.podspec b/RSKImageCropper.podspec index 193983e..96f80fb 100644 --- a/RSKImageCropper.podspec +++ b/RSKImageCropper.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'RSKImageCropper' - s.version = '4.1.1' + s.version = '5.0.0' s.summary = 'An image cropper for iOS like in the Contacts app with support for landscape orientation.' s.homepage = 'https://github.com/ruslanskorb/RSKImageCropper' s.license = { :type => 'MIT', :file => 'LICENSE' } diff --git a/RSKImageCropper.xcodeproj/project.pbxproj b/RSKImageCropper.xcodeproj/project.pbxproj index 80f76a0..2a48977 100644 --- a/RSKImageCropper.xcodeproj/project.pbxproj +++ b/RSKImageCropper.xcodeproj/project.pbxproj @@ -236,7 +236,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 4.1.1; + CURRENT_PROJECT_VERSION = 7; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; @@ -297,7 +297,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 4.1.1; + CURRENT_PROJECT_VERSION = 7; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; @@ -324,10 +324,10 @@ isa = XCBuildConfiguration; buildSettings = { CODE_SIGN_IDENTITY = ""; - CURRENT_PROJECT_VERSION = 5; + CURRENT_PROJECT_VERSION = 7; DEFINES_MODULE = YES; - DYLIB_COMPATIBILITY_VERSION = 4.1.1; - DYLIB_CURRENT_VERSION = 4.1.1; + DYLIB_COMPATIBILITY_VERSION = 5.0.0; + DYLIB_CURRENT_VERSION = 5.0.0; DYLIB_INSTALL_NAME_BASE = "@rpath"; ENABLE_MODULE_VERIFIER = YES; INFOPLIST_FILE = Framework/Info.plist; @@ -337,7 +337,7 @@ "@executable_path/Frameworks", "@loader_path/Frameworks", ); - MARKETING_VERSION = 4.1.1; + MARKETING_VERSION = 5.0.0; MODULEMAP_FILE = "$(SRCROOT)/RSKImageCropper/RSKImageCropper.modulemap"; MODULE_VERIFIER_SUPPORTED_LANGUAGES = "objective-c objective-c++"; MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu99 gnu++11"; @@ -351,10 +351,10 @@ isa = XCBuildConfiguration; buildSettings = { CODE_SIGN_IDENTITY = ""; - CURRENT_PROJECT_VERSION = 5; + CURRENT_PROJECT_VERSION = 7; DEFINES_MODULE = YES; - DYLIB_COMPATIBILITY_VERSION = 4.1.1; - DYLIB_CURRENT_VERSION = 4.1.1; + DYLIB_COMPATIBILITY_VERSION = 5.0.0; + DYLIB_CURRENT_VERSION = 5.0.0; DYLIB_INSTALL_NAME_BASE = "@rpath"; ENABLE_MODULE_VERIFIER = YES; INFOPLIST_FILE = Framework/Info.plist; @@ -364,7 +364,7 @@ "@executable_path/Frameworks", "@loader_path/Frameworks", ); - MARKETING_VERSION = 4.1.1; + MARKETING_VERSION = 5.0.0; MODULEMAP_FILE = "$(SRCROOT)/RSKImageCropper/RSKImageCropper.modulemap"; MODULE_VERIFIER_SUPPORTED_LANGUAGES = "objective-c objective-c++"; MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu99 gnu++11"; diff --git a/RSKImageCropper/RSKImageCropViewController.h b/RSKImageCropper/RSKImageCropViewController.h index 3e08d38..03d4c7a 100755 --- a/RSKImageCropper/RSKImageCropViewController.h +++ b/RSKImageCropper/RSKImageCropViewController.h @@ -59,7 +59,7 @@ NS_SWIFT_UI_ACTOR /** Zooms to a specific area of the image so that it is visible. - @param rect A rectangle defining an area of the image. The rectangle should be in the coordinate space of the image view controller's view. + @param rect A rectangle defining an area of the image. The rectangle should be in the coordinate space of the image crop view controller's view. @param animated YES if the scrolling should be animated, NO if it should be immediate. */ - (void)zoomToRect:(CGRect)rect animated:(BOOL)animated; diff --git a/RSKImageCropper/RSKImageCropViewController.m b/RSKImageCropper/RSKImageCropViewController.m index b763103..4d538b2 100644 --- a/RSKImageCropper/RSKImageCropViewController.m +++ b/RSKImageCropper/RSKImageCropViewController.m @@ -628,7 +628,11 @@ - (void)onChooseButtonTouch:(UIBarButtonItem *)sender - (void)handleDoubleTap:(UITapGestureRecognizer *)gestureRecognizer { - [self reset:YES]; + if (self.imageScrollView.zoomScale == self.zoomScaleDefaultValue) { + [self.imageScrollView zoomToLocation:[gestureRecognizer locationInView:self.imageScrollView] animated:YES]; + } else { + [self reset:YES]; + } } - (void)handleRotation:(UIRotationGestureRecognizer *)gestureRecognizer @@ -653,7 +657,7 @@ - (void)handleRotation:(UIRotationGestureRecognizer *)gestureRecognizer - (void)zoomToRect:(CGRect)rect animated:(BOOL)animated { rect = [self.imageScrollView convertRect:rect fromView:self.view]; - rect = [self.imageScrollView convertRect:rect toCoordinateSpace:self.imageScrollView.imageCoordinateSpace]; + rect = [self.imageScrollView convertRect:rect toCoordinateSpace:self.imageScrollView.imageViewCoordinateSpace]; [self.imageScrollView zoomToRect:rect animated:animated]; } @@ -678,6 +682,7 @@ - (void)reset:(BOOL)animated [self resetRotation]; [self resetZoomScale]; [self resetContentOffset]; + [self centerImage]; if (animated) { [UIView commitAnimations]; @@ -687,7 +692,7 @@ - (void)reset:(BOOL)animated - (void)resetContentOffset { CGSize boundsSize = self.imageScrollView.bounds.size; - CGRect frameToCenter = self.imageScrollView.imageFrame; + CGRect frameToCenter = self.imageScrollView.imageViewFrame; CGPoint contentOffset; if (CGRectGetWidth(frameToCenter) > boundsSize.width) { @@ -710,6 +715,11 @@ - (void)resetRotation } - (void)resetZoomScale +{ + self.imageScrollView.zoomScale = self.zoomScaleDefaultValue; +} + +- (CGFloat)zoomScaleDefaultValue { CGFloat zoomScale; if (CGRectGetWidth(self.view.bounds) > CGRectGetHeight(self.view.bounds)) { @@ -717,7 +727,7 @@ - (void)resetZoomScale } else { zoomScale = CGRectGetWidth(self.view.bounds) / self.originalImage.size.width; } - self.imageScrollView.zoomScale = zoomScale; + return zoomScale; } - (NSArray *)intersectionPointsOfLineSegment:(RSKLineSegment)lineSegment withRect:(CGRect)rect @@ -768,9 +778,9 @@ - (void)displayImage } } -- (void)centerImageScrollViewZoomView +- (void)centerImage { - // center imageScrollView.zoomView as it becomes smaller than the size of the screen + // center the image view of the imageScrollView as it becomes smaller than the size of the imageScrollView CGPoint contentOffset = self.imageScrollView.contentOffset; @@ -865,7 +875,7 @@ - (void)layoutImageScrollView self.imageScrollView.transform = CGAffineTransformIdentity; self.imageScrollView.frame = frame; - [self centerImageScrollViewZoomView]; + [self centerImage]; self.imageScrollView.transform = transform; } diff --git a/RSKImageCropper/RSKImageScrollView.h b/RSKImageCropper/RSKImageScrollView.h index e149d50..08bbfa6 100755 --- a/RSKImageCropper/RSKImageScrollView.h +++ b/RSKImageCropper/RSKImageScrollView.h @@ -1,7 +1,7 @@ /* File: RSKImageScrollView.h Abstract: Centers image within the scroll view and configures image sizing and display. - Version: 1.4 modified by Ruslan Skorb on 4/7/24. + Version: 1.5 modified by Ruslan Skorb on 11/26/24. Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Inc. ("Apple") in consideration of your agreement to the following @@ -69,33 +69,35 @@ NS_SWIFT_UI_ACTOR @property (nonatomic, nullable, strong) UIImage *image; /** - The color of the background behind the image. Default value is `nil`, which results in a transparent color. + The delegate of the image scroll view. - @discussion Changes to this property can be animated. + @discussion The delegate must adopt the `RSKImageScrollViewDelegate` protocol. The `RSKImageScrollView` class, which doesn’t retain the delegate, invokes each protocol method the delegate implements. */ -@property (nonatomic, nullable, strong) UIColor *imageBackgroundColor; +@property (nonatomic, nullable, weak) id imageScrollViewDelegate; /** - The coordinate space of the image. - */ -@property (nonatomic, readonly) id imageCoordinateSpace; + The logical dimensions, in points, of the image. Default value is `CGSizeZero`. + + @discussion Can be set to a value different from `image.size`. +*/ +@property (nonatomic, assign) CGSize imageSize; /** - The current frame of the image in the coordinate space of the image scroll view. + The background color of the image view. Default value is `nil`, which results in a transparent color. + + @discussion Changes to this property can be animated. */ -@property (nonatomic, readonly) CGRect imageFrame; +@property (nonatomic, nullable, strong) UIColor *imageViewBackgroundColor; /** - The delegate of the image scroll view. - - @discussion The delegate must adopt the `RSKImageScrollViewDelegate` protocol. The `RSKImageScrollView` class, which doesn’t retain the delegate, invokes each protocol method the delegate implements. + The coordinate space of the image view. */ -@property (nonatomic, nullable, weak) id imageScrollViewDelegate; +@property (nonatomic, readonly) id imageViewCoordinateSpace; /** - The logical dimensions, in points, of the image. Default value is `CGRectZero`. + The current frame of the image view in the coordinate space of the image scroll view. */ -@property (nonatomic, assign) CGSize imageSize; +@property (nonatomic, readonly) CGRect imageViewFrame; /** Sets the current scale factor applied to the image and offset from the image’s origin to the initial value. @@ -112,14 +114,6 @@ NS_SWIFT_UI_ACTOR */ - (void)zoomToLocation:(CGPoint)location animated:(BOOL)animated; -@end - -@interface RSKImageScrollView (Deprecated) - -@property (nonatomic, nullable, strong) UIImageView *zoomView __deprecated_msg("Please use 'image' and 'imageFrame' getters instead."); - -- (void)displayImage:(UIImage *)image __deprecated_msg("Please use 'image' setter instead."); - @end NS_HEADER_AUDIT_END(nullability, sendability) diff --git a/RSKImageCropper/RSKImageScrollView.m b/RSKImageCropper/RSKImageScrollView.m index 70e7a45..0f6836a 100755 --- a/RSKImageCropper/RSKImageScrollView.m +++ b/RSKImageCropper/RSKImageScrollView.m @@ -1,7 +1,7 @@ /* File: RSKImageScrollView.m Abstract: Centers image within the scroll view and configures image sizing and display. - Version: 1.4 modified by Ruslan Skorb on 4/7/24. + Version: 1.5 modified by Ruslan Skorb on 11/26/24. Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Inc. ("Apple") in consideration of your agreement to the following @@ -115,30 +115,29 @@ - (UIImage *)image - (void)setImage:(UIImage *)image { - UIImage *oldImage = _imageView.image; _imageView.image = image; - if (oldImage || !CGSizeEqualToSize(_imageSize, image.size)) { + if (CGSizeEqualToSize(_imageSize, CGSizeZero)) { self.imageSize = image.size; } } -- (UIColor *)imageBackgroundColor +- (UIColor *)imageViewBackgroundColor { return _imageView.backgroundColor; } -- (void)setImageBackgroundColor:(UIColor *)imageBackgroundColor +- (void)setImageViewBackgroundColor:(UIColor *)imageViewBackgroundColor { - _imageView.backgroundColor = imageBackgroundColor; + _imageView.backgroundColor = imageViewBackgroundColor; } -- (id)imageCoordinateSpace +- (id)imageViewCoordinateSpace { return [_imageView coordinateSpace]; } -- (CGRect)imageFrame +- (CGRect)imageViewFrame { return _imageView.frame; } @@ -200,9 +199,9 @@ - (void)setFrame:(CGRect)frame - (void)zoomToLocation:(CGPoint)location animated:(BOOL)animated { CGPoint locationInImageView = [_imageView convertPoint:location fromView:self]; - CGSize size = CGSizeMake(self.bounds.size.width / self.maximumZoomScale, - self.bounds.size.height / self.maximumZoomScale); - CGPoint origin = CGPointMake(locationInImageView.x - size.width * 0.5f, + CGSize size = CGSizeMake(self.bounds.size.width / MIN(self.zoomScale * 5.0f, self.maximumZoomScale), + self.bounds.size.height / MIN(self.zoomScale * 5.0f, self.maximumZoomScale)); + CGPoint origin = CGPointMake(locationInImageView.x - size.width * 0.5f, locationInImageView.y - size.height * 0.5f); CGRect rect = CGRectMake(origin.x, origin.y, size.width, size.height); @@ -440,34 +439,3 @@ - (CGPoint)minimumContentOffset } @end - -@implementation RSKImageScrollView (Deprecated) - -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wdeprecated-declarations" - -- (UIImageView *)zoomView { - - if (!_imageView.image) { - return nil; - } - return _imageView; -} - -- (void)setZoomView:(UIImageView *)zoomView { - - [_imageView removeFromSuperview]; - _imageView = zoomView; - if (_imageView) { - [self addSubview:_imageView]; - } -} - -- (void)displayImage:(UIImage *)image -{ - self.image = image; -} - -#pragma clang diagnostic pop - -@end