• Making the address
  • High imitation xiaohongshu App can drag and drop the tailoring function of any Angle

Introduction (Current version: 1.9.3)

A special clipping pictures, GIF, video tools, easy to use, rich features (high degree of freedom of parameter setting, support rotation and mirror rollover, mask, compression, etc.), can meet most of the needs of clipping.

Feature: ✅ can adapt to the scaling of the clipping region; ✅ High degree of freedom parameter setting, including the spacing of the cutting area, cutting aspect ratio, whether adaptive scaling; ✅ supports up to 8 drag direction clipping areas; ✅ support on the left right rotation; ✅ Horizontal and vertical mirror flip; ✅ two border styles; ✅ Supports cutting round boxes. ✅ custom frost-glass style, border color, background color, mask transparency; ✅ custom border pictures; ✅ can dynamically modify the view area and clipping area spacing, support horizontal and vertical switching; ✅ custom mask image cropping; ✅ can crop the whole local video screen or a frame screen; ✅ can intercept a local video, cut and converted into GIF; ✅ cropping GIF; ✅ can save the current clipping state; ✅ pictures support N grid cropping; ✅ Compatible with Swift. TODO: 🔘 Swift version; 🔘 Fixed unscaled clipping area; 🔘 Videos no longer need to be redirected and cropped; 🔘 Clip remote video; 🔘 Persistent cache cropping history; 🔘 separate the video cropping part (AVFoundation module); 🔘 to achieve apple album clipping function in the free drag rotation, flip Angle effect. Note: Since autoLayout is not good for gesture control, frame layout is used and autoLayout is not supported.Copy the code

How to use

Initialize the

1. Set initial parameters

- Image: cropped image /GIF (passed in as UIImage) - imageData: cropped image /GIF (passed in as NSData) - videoURL: cropped image /GIF (passed in as NSData) Cropped local video (passed as NSURL) -VideoAsset: Cropped local video (passed as AVURLAsset) Other part configurable parameters (see JPImageresizerView header for more information) : -Blureffect: Frosted Glass Style - borderImage - frameType & strokeColor: Border style & Color - bgColor: Background color - maskAlpha: Mask transparency - resizeWHScale: ContentInsets: the spacing between the clipped area and the view. MaskImage: the maskImageCopy the code
  • Image/GIF
// [cropped image /GIF] is passed in as UIImage
JPImageresizerConfigure *configure = [JPImageresizerConfigure defaultConfigureWithImage:image make:^(JPImageresizerConfigure *configure) {
    // The default parameter values are already there, so you can set the parameter values you want (using chained programming).
    configure
    .jp_maskAlpha(0.5)
    .jp_strokeColor([UIColor yellowColor])
    .jp_frameType(JPClassicFrameType)
    .jp_contentInsets(contentInsets)
    .jp_bgColor([UIColor orangeColor])
    .jp_isClockwiseRotation(YES)
    .jp_animationCurve(JPAnimationCurveEaseOut);
}];

// Set the resizeWHScale property of JPImageresizerConfigure if you want to initialize it to a square
configure.resizeWHScale = 1; // The default value is 0
// If a fixed ratio is required:
configure.isArbitrarily = YES; // The default is YES

// 2. [crop image /GIF] pass in NSData
JPImageresizerConfigure *configure = [JPImageresizerConfigure defaultConfigureWithImageData:imageData make:^(JPImageresizerConfigure *configure) { ...... };
Copy the code
  • video

About the photo album from the system for video, video may be modified in the direction (that is, the photo album rotate, flip), modified videoTrack. PreferredTransform! = CGAffineTransformIdentity images can also, but somehow the picture has a imageOrientation tells the specific what changed, because I’m pretty good, just pass preferredTransform doesn’t know is what are the specific changes, If only rotation is good, rotation + turnover after the value is not necessarily, so that the final cutting will be confused, we have to first correct the direction of the cutting, and then improve in the future, I hope to give advice!

Modify after initialization (enter the page first and then modify), the specific operation can refer to Demo:

// 1.  pass in NSURL
JPImageresizerConfigure *configure = [JPImageresizerConfigure defaultConfigureWithVideoURL:videoURL make:^(JPImageresizerConfigure *configure) { ...... } fixErrorBlock:^(NSURL *cacheURL, JPImageresizerErrorReason reason) {
    // Initialize the error callback to correct the video direction
} fixStartBlock:^{
    // Initialize the start callback to correct the video direction
} fixProgressBlock:^(float progress) {
    // Initialize the progress callback to correct the video direction
} fixCompleteBlock:^(NSURL *cacheURL) {
    // Initialize the completion callback to correct the video direction
}];

// 2.  AVURLAsset[JPImageresizerConfigure defaultConfigureWithVideoAsset:videoAsset make:^(JPImageresizerConfigure *configure) { ...... }  fixErrorBlock:^(NSURL *cacheURL, JPImageresizerErrorReason reason) { ...... } 
                                          fixStartBlock:^{ ...... } fixProgressBlock:^(float progress) { ...... } 
                                       fixCompleteBlock:^(NSURL *cacheURL) { ...... }];
Copy the code

You can use the API of JPImageresizerTool to modify, the specific operation can refer to Demo:

// Get the video information
AVURLAsset *videoAsset = [AVURLAsset assetWithURL:videoURL];
dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
[videoAsset loadValuesAsynchronouslyForKeys:@[@"duration".@"tracks"] completionHandler:^{
    dispatch_semaphore_signal(semaphore);
}];
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);

AVAssetTrack *videoTrack = [videoAsset tracksWithMediaType:AVMediaTypeVideo].firstObject;
if (CGAffineTransformEqualToTransform(videoTrack.preferredTransform, CGAffineTransformIdentity)) {
    // No need to modify, enter the clipping screen
    JPImageresizerConfigure *configure = [JPImageresizerConfigure defaultConfigureWithVideoAsset:videoAsset make:nil fixErrorBlock:nil fixStartBlock:nil fixProgressBlock:nil fixCompleteBlock:nil]; .return;
}

// Correct the direction
[JPImageresizerTool fixOrientationVideoWithAsset:videoAsset fixErrorBlock:^(NSURL *cacheURL, JPImageresizerErrorReason reason) {
    // Fix the incorrect callback for the video direction
} fixStartBlock:^(AVAssetExportSession *exportSession) {
    // Correct the start callback of the video direction
    // Return exportSession to monitor progress or cancel export
} fixCompleteBlock:^(NSURL *cacheURL) {
    // Correct the completion callback for the video direction
    // cacheURL: the final path to save the exported video. The default path is NSTemporaryDirectory. Save this path and delete the video after cropping.
    
    // Start clipping and enter the clipping screen
    JPImageresizerConfigure *configure = [JPImageresizerConfigure defaultConfigureWithVideoAsset:[AVURLAsset assetWithURL:cacheURL] make:nil fixErrorBlock:nil fixStartBlock:nil fixProgressBlock:nil fixCompleteBlock:nil]; . }];Copy the code
  • PS1: If the video doesn’t need fixing,fixStartBlock,fixProgressBlock,fixErrorBlockIt’s not called. It’s called directlyfixCompleteBlock, return to the original path;
  • PS2: If it is determined to be a video without direction correction,fixErrorBlock,fixStartBlock,fixProgressBlock,fixCompleteBlockthenil;
  • PS3: Replace video:-setVideoURL: animated: fixErrorBlock: fixStartBlock: fixProgressBlock: fixCompleteBlock:-setVideoAsset: animated: fixErrorBlock: fixStartBlock: fixProgressBlock: fixCompleteBlock:The same is true of the method, which internally determines whether it needs to be corrected;
  • PS4: If you need to initializefixedCutting aspect ratio (such as circular cut, mask, etc.), need to setJPImageresizerConfiguretheisArbitrarilyProperties forNO(Default: YES) :
JPImageresizerConfigure *configure = [JPImageresizerConfigure darkBlurMaskTypeConfigureWithImage:nil make:^(JPImageresizerConfigure *configure) {
    configure
    .jp_maskImage([UIImage imageNamed:@"love.png"])
    .jp_isArbitrarily(NO);
}];
Copy the code

2. Create a JPImageresizerView object and add it to the view

JPImageresizerView *imageresizerView = [JPImageresizerView imageresizerViewWithConfigure:configure imageresizerIsCanRecovery:^(BOOL isCanRecovery) {
    // You can listen here to see if it can be reset
    // If you do not need to reset (isCanRecovery to NO), you can do the corresponding processing here, for example, set the reset button to not click or hide
    // For details, see Demo
    // Notice circular references
} imageresizerIsPrepareToScale:^(BOOL isPrepareToScale) {
    // Here you can listen to whether the clipping area is ready to scale to the appropriate range
    // If isPrepareToScale is set to YES, then crop, rotate, and image functions are not available. For example, set the corresponding button to non-click or hide
    // For details, see Demo
    // Notice circular references
}];
[self.view addSubview:imageresizerView];
self.imageresizerView = imageresizerView;

// Configure parameters can be dynamically modified after being created
self.imageresizerView.image = [UIImage imageNamed:@"Kobe.jpg"]; // Change the crop image (default to draw)
self.imageresizerView.resizeWHScale = 16.0 / 9.0; // Modify the trim aspect ratio
self.imageresizerView.initialResizeWHScale = 0.0; / / by default initialization time resizeWHScale, call - recoveryByInitialResizeWHScale method to reset resizeWHScale will reset to the value of the attribute

/ / note: iOS11 system below, where the controller Settings automaticallyAdjustsScrollViewInsets best to NO
// Otherwise, the imageresizerView will be offset as the navigation bar or status bar changes
if (@available(iOS 11.0{}, *))else {
    self.automaticallyAdjustsScrollViewInsets = NO;
}
Copy the code

Use in Swift

// 1. Initial configuration
let configure = JPImageresizerConfigure.defaultConfigure(with: image) { c in
    _ = c
        .jp_viewFrame(frame)
        .jp_bgColor(.black)
        .jp_frameType(.classicFrameType)
        .jp_contentInsets(.init(top: 16, left: 16, bottom: 16, right: 16))
        .jp_animationCurve(.easeInOut)
}

// 2. Create imageresizerView
let imageresizerView = JPImageresizerView(configure: configure) { [weak self] isCanRecovery in
    // Do not click the reset button when no reset is required
    self?.recoveryBtn.isEnabled = isCanRecovery
} imageresizerIsPrepareToScale: { [weak self] isPrepareToScale in
    // When the zoom setting button is ready, it can be clicked
    self?.operationView.isUserInteractionEnabled = !isPrepareToScale
}

// 3. Add to the view
view.insertSubview(imageresizerView, at: 0)
self.imageresizerView = imageresizerView
Copy the code

You can download the Demo (JPCropViewController) from Github.

tailoring

Clipping description: 1. Clipping process is executed in the child thread, progress, error, complete callback will be cut back to the main thread execution, if it is hd picture, before clipping can add HUD prompt 2.compressScale: image and GIF compression ratio, greater than or equal to 1 according to the original image size clipping, less than or equal to 0 will return nil (example: CompressScale = 0.5, 1000 x 500 --> 500 x 250) Cache path, set to nil, images and GIFs are not cached, and videos are cached in NSTemporaryDirectory by default. The video is named current timestamp in mp4 4 format. -jpCEReason_NILObject: Clipped elements to be null -jpCEReason_CacheURLAlReadyExists: -jpCereason_nosupportedFileType: Indicates the unsupported file type. -jpCereason_VideoalReadyDamage: indicates the unsupported file type. The video file is damaged. - JPCEReason_VideoExportFailed: The video export fails. - JPCEReason_VideoExportCancelled: The video export is cancelledCopy the code

Cut out pictures

// 1. Cut to the original size
[self.imageresizerView cropPictureWithCacheURL:cacheURL errorBlock:^(NSURL *cacheURL, JPImageresizerErrorReason reason) {
    // Error callback
    // Reason: indicates the reason for the error
    // Notice circular references
} completeBlock:^(JPImageresizerResult *result) {
    // The cropping is complete
    // result: cropped result (JPImageresizerResult)
    // result. Image: image cropped (decoded)
    // result.cacheURL: destination path
    IsCacheSuccess: whether cache succeeded (cache failed if cacheURL is nil)
    // Notice circular references
}];


// 2. Customize the compression scale to crop the image
// compressScale -- return nil (example: compressScale = 0.5, 1000 x 500 --> 500 x 250)
// completeBlock -- callback after clipping (returns the clipping result, including the decoded picture, cache path)
- (void)cropPictureWithCompressScale:(CGFloat)compressScale
                            cacheURL:(NSURL *)cacheURL
                          errorBlock:(JPImageresizerErrorBlock)errorBlock
                       completeBlock:(JPCropDoneBlock)completeBlock;
Copy the code
  • Crop N grid image

// 1. Customize n-lattice clipping
// columnCount: number of columns (minimum 1 column)
// rowCount: number of rows in N cells (minimum 1 row)
// compressScale -- return nil (example: compressScale = 0.5, 1000 x 500 --> 500 x 250)
// bgColor -- N background color (only if the image has a transparent area, or if a mask is set, set the background color for the hidden area)
[self.imageresizerView cropGirdPicturesWithColumnCount:4 rowCount:2 compressScale:1 bgColor:UIColor.redColor cacheURL:cacheURL errorBlock:^(NSURL *cacheURL, JPImageresizerErrorReason reason) {
    // Error callback
    // Reason: indicates the reason for the error
    // Notice circular references
} completeBlock:^(JPImageresizerResult *originResult, NSArray<JPImageresizerResult *> *fragmentResults, NSInteger columnCount, NSInteger rowCount) {
    // The cropping is complete
    // originResult: the original result after cropping (before starting N grid)
    // fragmentResults: Set of results for the columnCount * rowCount
    // columnCount: Number of columns passed in when this method is called
    // rowCount: number of rows passed in when this method is called
    // Notice circular references
}];

// 2. Grid clipping (3 rows and 3 columns)
- (void)cropNineGirdPicturesWithCompressScale:(CGFloat)compressScale
                                      bgColor:(UIColor *)bgColor
                                     cacheURL:(NSURL *)cacheURL
                                   errorBlock:(JPImageresizerErrorBlock)errorBlock
                                completeBlock:(JPCropNGirdDoneBlock)completeBlock;
Copy the code

Share to friends (recommended to use resizeWHScale = 1 for cropping) :

Cut the GIF

// 1. Cut the original image size to GIF
[self.imageresizerView cropGIFWithCacheURL:cacheURL errorBlock:^(NSURL *cacheURL, JPImageresizerErrorReason reason) {
    // Error callback
    // Reason: indicates the reason for the error
    // Notice circular references
} completeBlock:^(JPImageresizerResult *result) {
    // The cropping is complete
    // result: cropped result (JPImageresizerResult)
    // result. Image: clipped GIF (decoded)
    // result.cacheURL: destination path
    IsCacheSuccess: whether cache succeeded (cache failed if cacheURL is nil)
    // Notice circular references
}];

// 2. Custom compression scale cropping GIF
// completeBlock -- callback after clipping (returns the clipping result, including the decoded GIF, cache path)
- (void)cropGIFWithCompressScale:(CGFloat)compressScale
                        cacheURL:(NSURL *)cacheURL
                      errorBlock:(JPImageresizerErrorBlock)errorBlock
                   completeBlock:(JPCropDoneBlock)completeBlock;

// 3. Customize cropping giFs
// isReverseOrder -- whether to reverse
// rate -- rate
// completeBlock -- callback after clipping (returns the clipping result, including the decoded GIF, cache path)
- (void)cropGIFWithCompressScale:(CGFloat)compressScale
                  isReverseOrder:(BOOL)isReverseOrder
                            rate:(float)rate
                        cacheURL:(NSURL *)cacheURL
                      errorBlock:(JPImageresizerErrorBlock)errorBlock
                   completeBlock:(JPCropDoneBlock)completeBlock;
Copy the code

Crop one frame of the GIF

// 1. Cut the GIF current frame to the original size
// completeBlock -- callback after clipping (returns the clipping result, including the decoded picture, cache path)
- (void)cropGIFCurrentIndexWithCacheURL:(NSURL *)cacheURL
                             errorBlock:(JPImageresizerErrorBlock)errorBlock
                          completeBlock:(JPCropDoneBlock)completeBlock;

// 2. Customize the compression ratio to crop the current GIF frame
// completeBlock -- callback after clipping (returns the clipping result, including the decoded picture, cache path)
- (void)cropGIFCurrentIndexWithCompressScale:(CGFloat)compressScale
                                    cacheURL:(NSURL *)cacheURL
                                  errorBlock:(JPImageresizerErrorBlock)errorBlock
                               completeBlock:(JPCropDoneBlock)completeBlock;

// 3. Custom compression scale cropping GIF specified frame screen
// index -- the number of frames
// compressScale -- return nil (example: compressScale = 0.5, 1000 x 500 --> 500 x 250)
- (void)cropGIFWithIndex:(NSUInteger)index
           compressScale:(CGFloat)compressScale
                cacheURL:(NSURL *)cacheURL
              errorBlock:(JPImageresizerErrorBlock)errorBlock
           completeBlock:(JPCropDoneBlock)completeBlock;
Copy the code
  • PS: You can set isLoopPlaybackGIF to choose which frame to crop (default is NO, set to YES will automatically play GIF)

self.imageresizerView.isLoopPlaybackGIF = NO;
Copy the code

Crop local video

  • PS: Currently, only local videos are available. Remote videos are not available.
// Clip the whole video
// cacheURL: If nil, the video is cached in the NSTemporaryDirectory folder in the system by default. The video is named the current timestamp in mp4 format
[self.imageresizerView cropVideoWithCacheURL:cacheURL errorBlock:^(NSURL *cacheURL, JPCropErrorReason reason) {
    // Error callback
    // Reason: indicates the reason for the error
    // Notice circular references
} progressBlock:^(float progress) {
    // Listen for progress
    / / progress: 0 ~ 1
    // Notice circular references
} completeBlock:^(JPImageresizerResult *result) {
    // The cropping is complete
    // result: cropped result (JPImageresizerResult)
    // Result. cacheURL: destination path. If nil, it will be cached to NSTemporaryDirectory folder in the system by default. The video name is the current timestamp and the format is MP4
    IsCacheSuccess: whether cache succeeded (cache failed if cacheURL is nil)
    // Notice circular references
}];

// You can set the video export quality
// presetName -- the quality of the system's video export, such as: AVAssetExportPresetLowQuality AVAssetExportPresetMediumQuality, AVAssetExportPresetHighestQuality, etc
- (void)cropVideoWithPresetName:(NSString *)presetName
                       cacheURL:(NSURL *)cacheURL 
                     errorBlock:(JPCropErrorBlock)errorBlock
                  progressBlock:(JPExportVideoProgressBlock)progressBlock
                  completeBlock:(JPCropDoneBlock)completeBlock;

// Cancel the video export
// Called when the video is being exported to cancel the export, triggering errorBlock callback (JPCEReason_ExportCancelled)
- (void)videoCancelExport;
Copy the code
  • PS: because of the video width must be integer times of 16 high, otherwise the system will automatically after the export to correction of size, shortage of place will fill in the form of green edge, so I am inside the method made for more than 16 except for cut size changes, so finally export video aspect ratio may have some differences with specified aspect ratio.

Crop one frame of a video

// 1. Clip the current frame of the video to the original size // cacheURL -- cache path (can be set to nil, it will not cache) // completeBlock -- callback to the completion of the clip (returns the result of the clip), Contains a decoded good image, the path of the cache) - (void) cropVideoCurrentFrameWithCacheURL: (cacheURL NSURL *) errorBlock:(JPImageresizerErrorBlock)errorBlock completeBlock:(JPCropDoneBlock)completeBlock; // 2. Clipping the current frame of the video with a custom compression ratio // cacheURL -- cache path (nil, no cache) // completeBlock -- callback after clipping (returns the result after clipping) Contains a decoded good image, the path of the cache) - (void) cropVideoCurrentFrameWithCompressScale: CGFloat compressScale cacheURL: (cacheURL NSURL *) errorBlock:(JPImageresizerErrorBlock)errorBlock completeBlock:(JPCropDoneBlock)completeBlock; // 3. Clip the video to a specified frame with a custom compression ratio // second -- the second frame // cacheURL -- the cache path (can be set to nil, it will not be cached) // completeBlock -- callback to the completion of the clip (returns the result of the clip), Contains a decoded good image, the path of the cache) - (void) cropVideoOneFrameWithSecond: (float) second compressScale: CGFloat compressScale cacheURL: (NSURL *)cacheURL errorBlock:(JPImageresizerErrorBlock)errorBlock completeBlock:(JPCropDoneBlock)completeBlock;Copy the code

Clip a segment of the video and convert it to GIF

(FPS = 10, rate = 1, maximumSize = 500 * 500)
// duration -- how many seconds to intercept
// completeBlock -- callback after clipping (returns the clipping result, including the decoded GIF, cache path)
- (void)cropVideoToGIFFromCurrentSecondWithDuration:(NSTimeInterval)duration
                                           cacheURL:(NSURL *)cacheURL
                                         errorBlock:(JPImageresizerErrorBlock)errorBlock
                                      completeBlock:(JPCropDoneBlock)completeBlock;

// 2. Custom video capture the specified number of seconds screen to GIF
// duration -- how many seconds to intercept
// FPS -- frame rate (set to 0 for real video frame rate)
// rate -- rate
// maximumSize -- the size of the capture (set to 0 for the real video size)
// completeBlock -- callback after clipping (returns the clipping result, including the decoded GIF, cache path)
- (void)cropVideoToGIFFromStartSecond:(NSTimeInterval)startSecond
                             duration:(NSTimeInterval)duration
                                  fps:(float)fps
                                 rate:(float)rate
                          maximumSize:(CGSize)maximumSize
                             cacheURL:(NSURL *)cacheURL
                           errorBlock:(JPImageresizerErrorBlock)errorBlock
                        completeBlock:(JPCropDoneBlock)completeBlock;
Copy the code
  • PS: Cropping the whole video screen circle cut, mask function is not available, currently only for images and GIFs.

The mask

// Set the mask image (currently only PNG images are supported)
self.imageresizerView.maskImage = [UIImage imageNamed:@"love.png"];

// To set this value directly is to call the -setmaskimage: istobejustification: animated: method, where istobejustification = (maskImage? NO: self.isArbitrarily), isreceptive = YES

// Remove the mask image
self.imageresizerView.maskImage = nil;
Copy the code
  • PS: If you use a mask, you will end up with a PNG image, so it may be larger than the original image.

Daniel Wu faces:

Circular cut

// Set the circular tangent
// After setting, the resizeWHScale is 1:1, the radius is half of the width and height, and the upper, left, lower and right middle parts of the frame can be dragged.
self.imageresizerView.isRoundResize = YES;

// Set this value directly to call the -setisroundresize: istobejustification: animated: method, where istobejustification = (isRoundResize? NO: self.isArbitrarily), isreceptive = YES

// Restore the rectangle
self.imageresizerView.isRoundResize = NO;
// Or just set resizeWHScale to any value
self.imageresizerView.resizeWHScale = 0.0;
Copy the code

Landscape and portrait switching

// Call this method to refresh when you need the user to listen for the horizontal and portrait toggle, or when you need to do it yourself
// 1. UpdateFrame: refresh Frame (e.g., to switch between portrait and landscape, pass in self.view.bounds)
// 2. ContentInsets: Trim the inner margins between the area and the main view
// 3.duration: refresh duration (greater than 0 means animation)
// Please refer to Demo for specific operation.
[self.imageresizerView updateFrame:self.view.bounds contentInsets:contentInsets duration:duration];
Copy the code

Change the border style

// Currently, there are only two frame styles, the concise style JPConciseFrameType and the classic style JPClassicFrameType
// The frameType property can be initialized or directly set to change the frame style
self.imageresizerView.frameType = JPClassicFrameType;
Copy the code

Custom border images

// Use custom border images (example: tile mode)
UIImage *tileBorderImage = [[UIImage imageNamed:@"jp_dotted_line"] resizableImageWithCapInsets:UIEdgeInsetsMake(14.14.14.14) resizingMode:UIImageResizingModeTile];

// Set the offset between the border image and the edge (CGRectInset)
self.imageresizerView.borderImageRectInset = CGPointMake(1.75.1.75);

// Set frame image (use frameType frame if nil)
self.imageresizerView.borderImage = tileBorderImage;
Copy the code

Switch cutting aspect ratio

  • PS: Setting the clipping aspect ratio will automatically remove the circular cut and mask
// 1. Customize parameter switching
/** * resizeWHScale: target resizeWHScale (0 = any ratio) * istobejustification: * Animated: whether or not to drive the painting effect */
[self.imageresizerView setResizeWHScale:(16.0 / 9.0) isToBeArbitrarily:YES animated:YES];

// 2. Switch directly
self.imageresizerView.resizeWHScale = 1.0;
// when you don't have any resizeWHScale, you don't have any resizeWHScale. When you don't, you don't have any resizeWHScale.
[self.imageresizerView setResizeWHScale:1.0 isToBeArbitrarily:(resizeWHScale <= 0) animated:YES];

// Can you drag and drop at any proportion (including circle cut, mask)
self.imageresizerView.isArbitrarily = !self.imageresizerView.isArbitrarily;

// See jpImageresizerView.h for more API comments
Copy the code

Custom frost-glass style, border color, background color, mask transparency

// Set the frosted glass style (by default)
self.imageresizerView.blurEffect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleDark];

// Set the border color (by default)
self.imageresizerView.strokeColor = UIColor.whiteColor;

// Set the background color (by default)
self.imageresizerView.bgColor = UIColor.blackColor;

// Set the opacity of the mask (by default)
// PS: is mutually exclusive with ground-glass. When ground-glass is set, the mask is transparent
self.imageresizerView.maskAlpha = 0.5; // blurEffect = nil

// Set the ground-glass style, border color, background color, and mask transparency
[self.imageresizerView setupStrokeColor:strokeColor blurEffect:[UIBlurEffect effectWithStyle:UIBlurEffectStyleDark] bgColor:UIColor.blackColor maskAlpha: 0.5 animated:YES];
Copy the code

Mirror flip

YES-> rotate 180° along the Y-axis, NO-> restore
BOOL isVerticalityMirror = !self.imageresizerView.verticalityMirror;
[self.imageresizerView setVerticalityMirror:isVerticalityMirror animated:YES];

YES-> rotate 180° along the X axis, NO-> restore
BOOL isHorizontalMirror = !self.imageresizerView.horizontalMirror;
[self.imageresizerView setHorizontalMirror:isHorizontalMirror animated:YES];
Copy the code

rotating

// The default rotation is counterclockwise, and the rotation Angle is 90°
[self.imageresizerView rotation];

// If clockwise rotation is required, set the isClockwiseRotation attribute to YES
self.imageresizerView.isClockwiseRotation = YES;
Copy the code

reset

Reset the target state, the direction is vertical up, can be reset to different resizeWHScale, circular tangent, mask

1. Reset everything according to the current status

- (void)recovery;
Copy the code

2. Reset with resizeWHScale (circular tangent and mask will be removed)

// 2.1 reset according to the initialResizeWHScale
- (void)recoveryByInitialResizeWHScale;
- (void)recoveryByInitialResizeWHScale:(BOOL)isToBeArbitrarily;

// 2.2 Reset the current clipping aspect ratio (if the resizeWHScale is 0, reset to the whole clipping element area)
- (void)recoveryByCurrentResizeWHScale;
- (void)recoveryByCurrentResizeWHScale:(BOOL)isToBeArbitrarily;

// 2.3 Resetting the target clipping aspect ratio (if the resizeWHScale is 0, reset to the whole clipping element area)
// targetResizeWHScale: Target clipping aspect ratio
Istobejustification: resizeWHScale = 0 when you reset it
- (void)recoveryToTargetResizeWHScale:(CGFloat)targetResizeWHScale isToBeArbitrarily:(BOOL)isToBeArbitrarily;
Copy the code

3. Reset by circular tangent

- (void)recoveryToRoundResize;
- (void)recoveryToRoundResize:(BOOL)isToBeArbitrarily;
Copy the code

4. Reset with a mask image

// 4.1 Reset the current mask image
- (void)recoveryByCurrentMaskImage;
- (void)recoveryByCurrentMaskImage:(BOOL)isToBeArbitrarily;

// 4.2 specifies a mask image reset
- (void)recoveryToMaskImage:(UIImage *)maskImage isToBeArbitrarily:(BOOL)isToBeArbitrarily;
Copy the code

preview

// Preview mode: hide the border, stop the drag and drop operation, and preview the clipped area

// 1. Built-in animation by default
self.imageresizerView.isPreview = YES;

// 2. Customize whether to drive the painting effect
[self.imageresizerView setIsPreview:YES animated:NO]
Copy the code

Saves the current clipping state

// 1. It is Easy to call saveCurrentConfigure to get the current clipping state. You can use a global variable to save the object
JPImageresizerConfigure *savedConfigure = [self.imageresizerView saveCurrentConfigure];

// 2. Open the cropping history again
JPImageresizerView *imageresizerView = [JPImageresizerView imageresizerViewWithConfigure:savedConfigure imageresizerIsCanRecovery:^(BOOL isCanRecovery) {
    ......
} imageresizerIsPrepareToScale:^(BOOL isPrepareToScale) {
    ......
}];
[self.view addSubview:imageresizerView];
self.imageresizerView = imageresizerView;

/ / 3. You can set the JPImageresizerConfigure isCleanHistoryAfterInitial attributes to YES, when the initialization is complete automatic emptying history (the default is YES)
// Or simply call the cleanHistory method to clear the history
Copy the code
  • PS1: If savedsavedConfigure.history.viewFrameWith the currentviewFrameInconsistent, the interface will lead to confusion, you need to judge whether consistent can be reopened;
  • PS2: In addition, it can only be saved during the use of the App, so there is no persistent cache.

other

// Lock the clipping area. If NO, the clipping area cannot be dragged
self.imageresizerView.isLockResizeFrame = YES;

// Whether to adapt the size of clipping area when rotating to the horizontal direction
// When the image width is smaller than the image height, this property defaults to YES, and can be manually set to NO
self.imageresizerView.isAutoScale = NO;
Copy the code

The installation

JPImageresizerView can be installed via CocoaPods, simply add the following line to your Podfile:

pod 'JPImageresizerView'
Copy the code

Feedback address

Email: [email protected] QQ: 184669029Copy the code