JPImageresizerView - 專門裁剪圖片、GIF、視頻的輪子(簡單易用、功能豐富)

效果圖

簡介(當前版本:1.11.4)

一個專門裁剪圖片、GIF、視頻的輪子,簡單易用,功能豐富(高自由度的參數(shù)設(shè)定、支持旋轉(zhuǎn)和鏡像翻轉(zhuǎn)、蒙版、壓縮等),能滿足絕大部分裁剪的需求。

Feature:
    ? 能自適應裁剪區(qū)域的縮放;
    ? 高自由度的參數(shù)設(shè)定,包括裁剪區(qū)域的間距、裁剪寬高比、是否自適應縮放等;
    ? 支持最多8個拖拽方向的裁剪區(qū)域;
    ? 支持上左下右的旋轉(zhuǎn);
    ? 水平和垂直的鏡像翻轉(zhuǎn);
    ? 兩種邊框樣式;
    ? 支持圓框裁剪;
    ? 自定義毛玻璃樣式、邊框顏色、背景顏色、遮罩透明度;
    ? 自定義邊框圖片;
    ? 可動態(tài)修改視圖區(qū)域和裁剪區(qū)域間距,支持橫豎屏切換;
    ? 可自定義蒙版圖片裁剪;
    ? 可裁剪本地視頻整段畫面或某一幀畫面;
    ? 可截取某一段本地視頻,裁剪后并轉(zhuǎn)成GIF;
    ? 可裁剪GIF;
    ? 可保存當前裁剪狀態(tài);
    ? 圖片支持N宮格裁剪;
    ? 兼容Swift&SwiftUI環(huán)境。

TODO:
    ?? Swift版本;
    ?? 固定不縮放裁剪區(qū)域;
    ?? 視頻不再需要修正方向再裁剪;
    ?? 裁剪遠程視頻;
    ?? 持久化緩存裁剪歷史;
    ?? 將視頻裁剪部分(AVFoundation模塊)分離出來;
    ?? 實現(xiàn)蘋果相冊裁剪功能中的自由拖拽旋轉(zhuǎn)、翻轉(zhuǎn)角度的效果。

注意:由于autoLayout不利于手勢控制,所以目前使用的是frame布局,暫不支持autoLayout。

最新改動

兼容Swift&SwiftUI環(huán)境。

如何使用

初始化

1. 配置初始參數(shù)

可設(shè)置的裁剪元素(圖片、GIF、視頻),只能選擇其中一個,并且不能為nil:
    - image:裁剪的圖片/GIF(以UIImage傳入)
    - imageData:裁剪的圖片/GIF(以NSData傳入)
    - videoURL:裁剪的本地視頻(以NSURL傳入)
    - videoAsset:裁剪的本地視頻(以AVURLAsset傳入)
    
其他部分可配置參數(shù)(更多可查看JPImageresizerView的頭文件):
    - blurEffect:毛玻璃樣式
    - borderImage:邊框圖片
    - frameType & strokeColor:邊框樣式&顏色
    - bgColor:背景色
    - maskAlpha:遮罩透明度
    - resizeWHScale:裁剪的寬高比
    - contentInsets:裁剪區(qū)域與視圖的間距
    - maskImage:蒙版圖片

圖片/GIF

//【裁剪的圖片/GIF】以UIImage傳入
JPImageresizerConfigure *configure = [JPImageresizerConfigure defaultConfigureWithImage:image make:^(JPImageresizerConfigure *configure) {
    // 到這里已經(jīng)有了默認參數(shù)值,可以在這里另外設(shè)置你想要的參數(shù)值(使用了鏈式編程方式)
    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);
}];

// 如果想要初始化為正方形,可設(shè)置 JPImageresizerConfigure 的 resizeWHScale 屬性
configure.resizeWHScale = 1; // 默認為0,完全顯示
// 另外如果還需要固定比例的話:
configure.isArbitrarily = YES; // 默認為YES

// 2.【裁剪的圖片/GIF】以NSData傳入
JPImageresizerConfigure *configure = [JPImageresizerConfigure defaultConfigureWithImageData:imageData make:^(JPImageresizerConfigure *configure) { ...... };

視頻

關(guān)于從系統(tǒng)相冊獲取的視頻,視頻方向有可能是修改過的(即相冊中旋轉(zhuǎn)、翻轉(zhuǎn)過),修改后的videoTrack.preferredTransform != CGAffineTransformIdentity,圖片也會,不過好歹圖片有個imageOrientation屬性告知具體改動了什么,由于我才疏學淺,單單從preferredTransform并不知道是經(jīng)過了具體的哪些改動,如果只是旋轉(zhuǎn)還好,旋轉(zhuǎn)+翻轉(zhuǎn)后的數(shù)值都是不一定的,這樣導致最后裁剪時會錯亂,目前只好先修正方向后再進行裁剪,日后改進,希望能有緣之士給予指點!

初始化后再修正(先進入頁面后再修正),具體操作可參照Demo:

// 1.【視頻】以NSURL傳入
JPImageresizerConfigure *configure = [JPImageresizerConfigure defaultConfigureWithVideoURL:videoURL make:^(JPImageresizerConfigure *configure) { ...... } fixErrorBlock:^(NSURL *cacheURL, JPImageresizerErrorReason reason) {
    // 初始化修正視頻方向的錯誤回調(diào)
} fixStartBlock:^{
    // 初始化修正視頻方向的開始回調(diào)
} fixProgressBlock:^(float progress) {
    // 初始化修正視頻方向的進度回調(diào) 
} fixCompleteBlock:^(NSURL *cacheURL) {
    // 初始化修正視頻方向的完成回調(diào)
}];

// 2.【視頻】以AVURLAsset傳入
[JPImageresizerConfigure defaultConfigureWithVideoAsset:videoAsset 
                                                   make:^(JPImageresizerConfigure *configure) { ...... } 
                                          fixErrorBlock:^(NSURL *cacheURL, JPImageresizerErrorReason reason) { ...... } 
                                          fixStartBlock:^{ ...... } fixProgressBlock:^(float progress) { ...... } 
                                       fixCompleteBlock:^(NSURL *cacheURL) { ...... }];

又或者先修正再初始化(先修正后再進入頁面),可以使用JPImageresizerTool的API來修正,具體操作可參照Demo:

// 獲取視頻信息
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)) {
    // 無需修正,進入裁剪界面
    JPImageresizerConfigure *configure = [JPImageresizerConfigure defaultConfigureWithVideoAsset:videoAsset make:nil fixErrorBlock:nil fixStartBlock:nil fixProgressBlock:nil fixCompleteBlock:nil];
    ......
    return;
}

// 修正方向
[JPImageresizerTool fixOrientationVideoWithAsset:videoAsset fixErrorBlock:^(NSURL *cacheURL, JPImageresizerErrorReason reason) {
    // 修正視頻方向的錯誤回調(diào)
} fixStartBlock:^(AVAssetExportSession *exportSession) {
    // 修正視頻方向的開始回調(diào)
    // 返回exportSession,可監(jiān)聽進度或取消導出
} fixCompleteBlock:^(NSURL *cacheURL) {
    // 修正視頻方向的完成回調(diào)
    // cacheURL:修正方向后的視頻導出后的最終存放路徑,默認該路徑為NSTemporaryDirectory文件夾下,保存該路徑,裁剪后刪除視頻。
    
    // 開始裁剪,進入裁剪界面
    JPImageresizerConfigure *configure = [JPImageresizerConfigure defaultConfigureWithVideoAsset:[AVURLAsset assetWithURL:cacheURL] make:nil fixErrorBlock:nil fixStartBlock:nil fixProgressBlock:nil fixCompleteBlock:nil];
    ......
}];
  • PS1:如果視頻不需要修正,fixStartBlock、fixProgressBlock、fixErrorBlock均不會調(diào)用,會直接調(diào)用fixCompleteBlock,返回原路徑;
  • PS2:如果確定是無需修正方向的視頻,fixErrorBlock、fixStartBlock、fixProgressBlockfixCompleteBlocknil;
  • PS3:更換視頻:-setVideoURL: animated: fixErrorBlock: fixStartBlock: fixProgressBlock: fixCompleteBlock:-setVideoAsset: animated: fixErrorBlock: fixStartBlock: fixProgressBlock: fixCompleteBlock: 方法也與之同理,內(nèi)部會判定是否需要修正;
  • PS4:如果需要初始化就固定裁剪寬高比(如圓切、蒙版等),需要設(shè)置JPImageresizerConfigureisArbitrarily屬性為NO(默認為YES):
JPImageresizerConfigure *configure = [JPImageresizerConfigure darkBlurMaskTypeConfigureWithImage:nil make:^(JPImageresizerConfigure *configure) {
    configure
    .jp_maskImage([UIImage imageNamed:@"love.png"])
    .jp_isArbitrarily(NO);
}];

2. 創(chuàng)建JPImageresizerView對象并添加到視圖上

JPImageresizerView *imageresizerView = [JPImageresizerView imageresizerViewWithConfigure:configure imageresizerIsCanRecovery:^(BOOL isCanRecovery) {
    // 可在這里監(jiān)聽到是否可以重置
    // 如果不需要重置(isCanRecovery為NO),可在這里做相應處理,例如將重置按鈕設(shè)置為不可點或隱藏
    // PS:isCanRecovery僅針對[旋轉(zhuǎn)]、[縮放]、[鏡像]的變化情況,其他如裁剪寬高比、圓切等變化情況需用戶自行判定能否重置
    // 具體操作可參照Demo
    // 注意循環(huán)引用
} imageresizerIsPrepareToScale:^(BOOL isPrepareToScale) {
    // 可在這里監(jiān)聽到裁剪區(qū)域是否預備縮放至適合范圍
    // 如果預備縮放(isPrepareToScale為YES),此時裁剪、旋轉(zhuǎn)、鏡像功能不可用,可在這里做相應處理,例如將對應按鈕設(shè)置為不可點或隱藏
    // 具體操作可參照Demo
    // 注意循環(huán)引用
}];
[self.view addSubview:imageresizerView];
self.imageresizerView = imageresizerView;

// 創(chuàng)建后均可動態(tài)修改configure的參數(shù)
self.imageresizerView.image = [UIImage imageNamed:@"Kobe.jpg"]; // 更換裁剪圖片(默認帶動畫效果)
self.imageresizerView.resizeWHScale = 16.0 / 9.0; // 修改裁剪寬高比
self.imageresizerView.initialResizeWHScale = 0.0; // 默認為初始化時的resizeWHScale,調(diào)用 -recoveryByInitialResizeWHScale 方法進行重置則 resizeWHScale 會重置為該屬性的值

// 注意:iOS11以下的系統(tǒng),所在的controller最好設(shè)置automaticallyAdjustsScrollViewInsets為NO
// 不然imageresizerView會隨導航欄或狀態(tài)欄的變化產(chǎn)生偏移
if (@available(iOS 11.0, *)) {

} else {
    self.automaticallyAdjustsScrollViewInsets = NO;
}

在Swift中的使用

// 1.初始配置
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.創(chuàng)建imageresizerView
let imageresizerView = JPImageresizerView(configure: configure) { [weak self] isCanRecovery in
    // 當不需要重置設(shè)置按鈕不可點
    self?.recoveryBtn.isEnabled = isCanRecovery
} imageresizerIsPrepareToScale: { [weak self] isPrepareToScale in
    // 當預備縮放設(shè)置按鈕不可點,結(jié)束后可點擊
    self?.operationView.isUserInteractionEnabled = !isPrepareToScale
}

// 3.添加到視圖上
view.insertSubview(imageresizerView, at: 0)
self.imageresizerView = imageresizerView

具體使用可以去Github下載Demo查看(JPCropViewController)。

裁剪

裁剪說明:
    1.裁剪過程是在子線程中執(zhí)行,進度、錯誤、完成的回調(diào)都會切回主線程執(zhí)行,如果是高清圖片,裁剪前可添加HUD提示;
    2.compressScale:圖片和GIF的壓縮比例,大于等于1按原圖尺寸裁剪,小于等于0則返回nil(例:compressScale = 0.5,1000 x 500 --> 500 x 250);
    3.cacheURL:緩存路徑,可設(shè)置為nil,圖片和GIF則不緩存,而視頻會默認緩存到系統(tǒng)的NSTemporaryDirectory文件夾下,視頻名為當前時間戳,格式為mp4;
    4.錯誤原因 JPCropErrorReason 說明:
        - JPCEReason_NilObject:裁剪元素為空
        - JPCEReason_CacheURLAlreadyExists:緩存路徑已存在其他文件
        - JPCEReason_NoSupportedFileType:不支持的文件類型
        - JPCEReason_VideoAlreadyDamage:視頻文件已損壞
        - JPCEReason_VideoExportFailed:視頻導出失敗
        - JPCEReason_VideoExportCancelled:視頻導出取消
    5.注意:緩存路徑的圖片格式會自動修正,例如原本寫的是`xxx/xxx.jpeg`,由于使用了蒙版,裁剪后則會修正為`xxx/xxx.png`了,最終的緩存路徑要以裁剪回調(diào)`completeBlock`中的`result.cacheURL`為準。

裁剪圖片

// 1.以原圖尺寸進行裁剪
[self.imageresizerView cropPictureWithCacheURL:cacheURL errorBlock:^(NSURL *cacheURL, JPImageresizerErrorReason reason) {
    // 錯誤的回調(diào)
    // reason:錯誤原因
    // 注意循環(huán)引用
} completeBlock:^(JPImageresizerResult *result) {
    // 裁剪完成
    // result:裁剪后的結(jié)果(JPImageresizerResult)
    // result.image:裁剪后的圖片(已解碼好的)
    // result.cacheURL:目標存放路徑
    // result.isCacheSuccess:是否緩存成功(緩存不成功則cacheURL為nil)
    // 注意循環(huán)引用
}];


// 2.自定義壓縮比例裁剪圖片
// compressScale --- 壓縮比例,大于等于1按原圖尺寸裁剪,小于等于0則返回nil(例:compressScale = 0.5,1000 x 500 --> 500 x 250)
// completeBlock --- 裁剪完成的回調(diào)(返回裁剪后的結(jié)果,包含已解碼好的圖片、緩存路徑)
- (void)cropPictureWithCompressScale:(CGFloat)compressScale
                            cacheURL:(NSURL *)cacheURL
                          errorBlock:(JPImageresizerErrorBlock)errorBlock
                       completeBlock:(JPCropDoneBlock)completeBlock;
  • 裁剪N宮格圖片
image
// 1.自定義N宮格裁剪
// columnCount:N宮格的列數(shù)(最小1列)
// rowCount:N宮格的行數(shù)(最小1行)
// compressScale --- 壓縮比例,大于等于1按原圖尺寸裁剪,小于等于0則返回nil(例:compressScale = 0.5,1000 x 500 --> 500 x 250)
// bgColor --- N宮格的背景色(如果圖片有透明區(qū)域,或者設(shè)置了蒙版的情況才生效,設(shè)置隱藏(透明)區(qū)域的背景色)
[self.imageresizerView cropGirdPicturesWithColumnCount:4 rowCount:2 compressScale:1 bgColor:UIColor.redColor cacheURL:cacheURL errorBlock:^(NSURL *cacheURL, JPImageresizerErrorReason reason) {
    // 錯誤的回調(diào)
    // reason:錯誤原因
    // 注意循環(huán)引用
} completeBlock:^(JPImageresizerResult *originResult, NSArray<JPImageresizerResult *> *fragmentResults, NSInteger columnCount, NSInteger rowCount) {
    // 裁剪完成
    // originResult:裁剪后的原圖結(jié)果(開始N宮格之前)
    // fragmentResults:裁剪后的原圖被裁剪成N宮格圖片的結(jié)果集合(共 columnCount * rowCount 個)
    // columnCount:調(diào)用該方法時傳入的列數(shù)
    // rowCount:調(diào)用該方法時傳入的行數(shù)
    // 注意循環(huán)引用
}];

// 2.九宮格裁剪(3行3列)
- (void)cropNineGirdPicturesWithCompressScale:(CGFloat)compressScale
                                      bgColor:(UIColor *)bgColor
                                     cacheURL:(NSURL *)cacheURL
                                   errorBlock:(JPImageresizerErrorBlock)errorBlock
                                completeBlock:(JPCropNGirdDoneBlock)completeBlock;

分享至朋友圈(建議使用resizeWHScale = 1進行裁剪):

image

裁剪GIF

image
image
// 1.原圖尺寸裁剪GIF
[self.imageresizerView cropGIFWithCacheURL:cacheURL errorBlock:^(NSURL *cacheURL, JPImageresizerErrorReason reason) {
    // 錯誤的回調(diào)
    // reason:錯誤原因
    // 注意循環(huán)引用
} completeBlock:^(JPImageresizerResult *result) {
    // 裁剪完成
    // result:裁剪后的結(jié)果(JPImageresizerResult)
    // result.image:裁剪后的GIF(已解碼好的)
    // result.cacheURL:目標存放路徑
    // result.isCacheSuccess:是否緩存成功(緩存不成功則cacheURL為nil)
    // 注意循環(huán)引用
}];

// 2.自定義壓縮比例裁剪GIF
// completeBlock --- 裁剪完成的回調(diào)(返回裁剪后的結(jié)果,包含已解碼好的GIF、緩存路徑)
- (void)cropGIFWithCompressScale:(CGFloat)compressScale
                        cacheURL:(NSURL *)cacheURL
                      errorBlock:(JPImageresizerErrorBlock)errorBlock
                   completeBlock:(JPCropDoneBlock)completeBlock;

// 3.自定義裁剪GIF
// isReverseOrder --- 是否倒放
// rate --- 速率
// completeBlock --- 裁剪完成的回調(diào)(返回裁剪后的結(jié)果,包含已解碼好的GIF、緩存路徑)
- (void)cropGIFWithCompressScale:(CGFloat)compressScale
                  isReverseOrder:(BOOL)isReverseOrder
                            rate:(float)rate
                        cacheURL:(NSURL *)cacheURL
                      errorBlock:(JPImageresizerErrorBlock)errorBlock
                   completeBlock:(JPCropDoneBlock)completeBlock;

裁剪GIF的其中一幀

// 1.原圖尺寸裁剪GIF當前幀畫面
// completeBlock --- 裁剪完成的回調(diào)(返回裁剪后的結(jié)果,包含已解碼好的圖片、緩存路徑)
- (void)cropGIFCurrentIndexWithCacheURL:(NSURL *)cacheURL
                             errorBlock:(JPImageresizerErrorBlock)errorBlock
                          completeBlock:(JPCropDoneBlock)completeBlock;

// 2.自定義壓縮比例裁剪GIF當前幀畫面
// completeBlock --- 裁剪完成的回調(diào)(返回裁剪后的結(jié)果,包含已解碼好的圖片、緩存路徑)
- (void)cropGIFCurrentIndexWithCompressScale:(CGFloat)compressScale
                                    cacheURL:(NSURL *)cacheURL
                                  errorBlock:(JPImageresizerErrorBlock)errorBlock
                               completeBlock:(JPCropDoneBlock)completeBlock;

// 3.自定義壓縮比例裁剪GIF指定幀畫面
// index --- 第幾幀畫面
// compressScale --- 壓縮比例,大于等于1按原圖尺寸裁剪,小于等于0則返回nil(例: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;
  • PS:可以設(shè)置isLoopPlaybackGIF自主選擇裁剪哪一幀(默認為NO,設(shè)置為YES會自動播放GIF)
image
self.imageresizerView.isLoopPlaybackGIF = NO;

裁剪本地視頻

裁剪本地視頻
  • PS:目前只針對本地視頻,遠程視頻暫未適配。
// 裁剪整段視頻
// cacheURL:如果為nil,會默認緩存到系統(tǒng)的NSTemporaryDirectory文件夾下,視頻名為當前時間戳,格式為mp4
[self.imageresizerView cropVideoWithCacheURL:cacheURL errorBlock:^(NSURL *cacheURL, JPCropErrorReason reason) {
    // 錯誤的回調(diào)
    // reason:錯誤原因
    // 注意循環(huán)引用
} progressBlock:^(float progress) {
    // 監(jiān)聽進度
    // progress:0~1
    // 注意循環(huán)引用
} completeBlock:^(JPImageresizerResult *result) {
    // 裁剪完成
    // result:裁剪后的結(jié)果(JPImageresizerResult)
    // result.cacheURL:目標存放路徑,如果為nil,會默認緩存到系統(tǒng)的NSTemporaryDirectory文件夾下,視頻名為當前時間戳,格式為mp4
    // result.isCacheSuccess:是否緩存成功(緩存不成功則cacheURL為nil)
    // 注意循環(huán)引用
}];

// 可設(shè)置視頻導出質(zhì)量
// presetName --- 系統(tǒng)的視頻導出質(zhì)量,如:AVAssetExportPresetLowQuality,AVAssetExportPresetMediumQuality,AVAssetExportPresetHighestQuality等
- (void)cropVideoWithPresetName:(NSString *)presetName
                       cacheURL:(NSURL *)cacheURL 
                     errorBlock:(JPCropErrorBlock)errorBlock
                  progressBlock:(JPExportVideoProgressBlock)progressBlock
                  completeBlock:(JPCropDoneBlock)completeBlock;

// 取消視頻導出
// 當視頻正在導出時調(diào)用即可取消導出,觸發(fā)errorBlock回調(diào)(JPCEReason_ExportCancelled)
- (void)videoCancelExport;
  • PS:由于視頻的寬高都必須是16的整數(shù)倍,否則導出后系統(tǒng)會自動對尺寸進行校正,不足的地方會以綠邊的形式進行填充,因此我在方法內(nèi)部對裁剪尺寸做了對16除余的修改,所以最后導出視頻的寬高比有可能跟指定的寬高比有些許差異。

裁剪視頻的其中一幀

// 1.原圖尺寸裁剪視頻當前幀畫面
// cacheURL --- 緩存路徑(可設(shè)置為nil,則不會緩存)
// completeBlock --- 裁剪完成的回調(diào)(返回裁剪后的結(jié)果,包含已解碼好的圖片、緩存路徑)
- (void)cropVideoCurrentFrameWithCacheURL:(NSURL *)cacheURL
                               errorBlock:(JPImageresizerErrorBlock)errorBlock
                            completeBlock:(JPCropDoneBlock)completeBlock;

// 2.自定義壓縮比例裁剪視頻當前幀畫面
// cacheURL --- 緩存路徑(可設(shè)置為nil,則不會緩存)
// completeBlock --- 裁剪完成的回調(diào)(返回裁剪后的結(jié)果,包含已解碼好的圖片、緩存路徑)
- (void)cropVideoCurrentFrameWithCompressScale:(CGFloat)compressScale
                                      cacheURL:(NSURL *)cacheURL
                                    errorBlock:(JPImageresizerErrorBlock)errorBlock
                                 completeBlock:(JPCropDoneBlock)completeBlock;

// 3.自定義壓縮比例裁剪視頻指定幀畫面
// second --- 第幾秒畫面
// cacheURL --- 緩存路徑(可設(shè)置為nil,則不會緩存)
// completeBlock --- 裁剪完成的回調(diào)(返回裁剪后的結(jié)果,包含已解碼好的圖片、緩存路徑)
- (void)cropVideoOneFrameWithSecond:(float)second
                      compressScale:(CGFloat)compressScale
                           cacheURL:(NSURL *)cacheURL
                         errorBlock:(JPImageresizerErrorBlock)errorBlock
                      completeBlock:(JPCropDoneBlock)completeBlock;

截取視頻某一段裁剪后轉(zhuǎn)GIF

截取視頻轉(zhuǎn)GIF
// 1.視頻從當前時間開始截取指定秒數(shù)畫面轉(zhuǎn)GIF(fps = 10,rate = 1,maximumSize = 500 * 500)
// duration --- 截取多少秒
// completeBlock --- 裁剪完成的回調(diào)(返回裁剪后的結(jié)果,包含已解碼好的GIF、緩存路徑)
- (void)cropVideoToGIFFromCurrentSecondWithDuration:(NSTimeInterval)duration
                                           cacheURL:(NSURL *)cacheURL
                                         errorBlock:(JPImageresizerErrorBlock)errorBlock
                                      completeBlock:(JPCropDoneBlock)completeBlock;

// 2.視頻自定義截取指定秒數(shù)畫面轉(zhuǎn)GIF
// duration --- 截取多少秒
// fps --- 幀率(設(shè)置為0則以視頻真身幀率)
// rate --- 速率
// maximumSize --- 截取的尺寸(設(shè)置為0則以視頻真身尺寸)
// completeBlock --- 裁剪完成的回調(diào)(返回裁剪后的結(jié)果,包含已解碼好的GIF、緩存路徑)
- (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;
  • PS:裁剪整段視頻畫面圓切、蒙版的功能不能使用,目前只對圖片和GIF有效。

蒙版

mask
// 設(shè)置蒙版圖片(目前僅支持png圖片)
self.imageresizerView.maskImage = [UIImage imageNamed:@"love.png"];

// 直接設(shè)置該值即是調(diào)用 -setMaskImage: isToBeArbitrarily: animated: 方法,其中默認 isToBeArbitrarily = (maskImage ? NO : self.isArbitrarily),isAnimated = YES

// 移除蒙版圖片
self.imageresizerView.maskImage = nil;
maskdone
  • PS:如果使用了蒙版圖片,那么最后裁剪出來的是png圖片,因此裁剪后體積有可能會比原本的圖片更大。


    吳彥祖換臉

圓切

圓切
// 設(shè)置圓切
// 設(shè)置后,resizeWHScale為1:1,半徑為寬高的一半,邊框的上、左、下、右的中部均可拖動。
self.imageresizerView.isRoundResize = YES;

// 直接設(shè)置該值即是調(diào)用 -setIsRoundResize: isToBeArbitrarily: animated: 方法,其中默認 isToBeArbitrarily = (isRoundResize ? NO : self.isArbitrarily),isAnimated = YES

// 還原矩形
self.imageresizerView.isRoundResize = NO;
// 或者只需設(shè)置一下resizeWHScale為任意值即可
self.imageresizerView.resizeWHScale = 0.0;

橫豎屏切換

screenswitching
// 需要用戶去監(jiān)聽橫豎屏的切換,或自己手動切換時,調(diào)用該方法刷新
// 1.updateFrame:刷新的Frame(例如橫豎屏切換,傳入self.view.bounds即可)
// 2.contentInsets:裁剪區(qū)域與主視圖的內(nèi)邊距
// 3.duration:刷新時長(大于0即帶有動畫效果)
//【具體操作可參照Demo】
[self.imageresizerView updateFrame:self.view.bounds contentInsets:contentInsets duration:duration];

更改邊框樣式

簡潔風格
經(jīng)典風格
// 目前只提供兩種邊框樣式,分別是簡潔樣式JPConciseFrameType,和經(jīng)典樣式JPClassicFrameType
// 可在初始化或直接設(shè)置frameType屬性來修改邊框樣式
self.imageresizerView.frameType = JPClassicFrameType;

自定義邊框圖片

拉伸模式
平鋪模式
// 使用自定義邊框圖片(例:平鋪模式)
UIImage *tileBorderImage = [[UIImage imageNamed:@"jp_dotted_line"] resizableImageWithCapInsets:UIEdgeInsetsMake(14, 14, 14, 14) resizingMode:UIImageResizingModeTile];

// 設(shè)置邊框圖片與邊線的偏移量(即CGRectInset,用于調(diào)整邊框圖片與邊線的差距)
self.imageresizerView.borderImageRectInset = CGPointMake(-1.75, -1.75);

// 設(shè)置邊框圖片(若為nil則使用frameType的邊框)
self.imageresizerView.borderImage = tileBorderImage;

切換裁剪寬高比

  • PS:設(shè)置裁剪寬高比會自動移除圓切和蒙版
// 1.自定義參數(shù)切換
/**
 * resizeWHScale:    目標裁剪寬高比(0則為任意比例)
 * isToBeArbitrarily:切換之后 resizeWHScale 是否為任意比例(若為YES,最后 resizeWHScale = 0)
 * animated:         是否帶動畫效果
 */
[self.imageresizerView setResizeWHScale:(16.0 / 9.0) isToBeArbitrarily:YES animated:YES];

// 2.直接切換
self.imageresizerView.resizeWHScale = 1.0;
// 默認切換之后保存最新的 resizeWHScale,且自帶動畫效果,如果設(shè)置為0,以當前裁剪框的寬高比設(shè)置,并且最后 isArbitrarily = YES,相當于:
[self.imageresizerView setResizeWHScale:1.0 isToBeArbitrarily:(resizeWHScale <= 0) animated:YES];

// 是否可以任意比例拖拽(包括圓切、蒙版)
self.imageresizerView.isArbitrarily = !self.imageresizerView.isArbitrarily;

// 更多API可查看 JPImageresizerView.h 上的注釋

自定義毛玻璃樣式、邊框顏色、背景顏色、遮罩透明度

// 設(shè)置毛玻璃樣式(默認帶動畫效果)
self.imageresizerView.blurEffect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleDark];

// 設(shè)置邊框顏色(默認帶動畫效果)
self.imageresizerView.strokeColor = UIColor.whiteColor;

// 設(shè)置背景顏色(默認帶動畫效果)
self.imageresizerView.bgColor = UIColor.blackColor;

// 設(shè)置遮罩透明度(默認帶動畫效果)
// PS:跟毛玻璃互斥,當設(shè)置了毛玻璃則遮罩為透明
self.imageresizerView.maskAlpha = 0.5; // blurEffect = nil 才生效

// 一步設(shè)置毛玻璃樣式、邊框顏色、背景顏色、遮罩透明度
[self.imageresizerView setupStrokeColor:strokeColor blurEffect:[UIBlurEffect effectWithStyle:UIBlurEffectStyleDark] bgColor:UIColor.blackColor maskAlpha: 0.5 animated:YES];

鏡像翻轉(zhuǎn)

效果圖.gif
// 垂直鏡像,YES->沿著Y軸旋轉(zhuǎn)180°,NO->還原
BOOL isVerticalityMirror = !self.imageresizerView.verticalityMirror;
[self.imageresizerView setVerticalityMirror:isVerticalityMirror animated:YES];

// 水平鏡像,YES->沿著X軸旋轉(zhuǎn)180°,NO->還原
BOOL isHorizontalMirror = !self.imageresizerView.horizontalMirror;
[self.imageresizerView setHorizontalMirror:isHorizontalMirror animated:YES];

旋轉(zhuǎn)

// 1.順/逆時針旋轉(zhuǎn)90°(默認逆時針)
[self.imageresizerView rotation];

// 若需要順時針旋轉(zhuǎn)可設(shè)置isClockwiseRotation屬性為YES
self.imageresizerView.isClockwiseRotation = YES;

// 2.自定義旋轉(zhuǎn)至目標方向(支持4個方向,分別是垂直向上、水平向左、垂直向下、水平向右)
[self.imageresizerView rotationToDirection:JPImageresizerVerticalDownDirection];

重置

重置目標狀態(tài),方向垂直向上,可重置為不同的resizeWHScale、圓切、蒙版

1. 一切按當前狀態(tài)重置

- (void)recovery;

2. 以resizeWHScale重置(會移除圓切、蒙版)

// 2.1 按初始裁剪寬高比(initialResizeWHScale)進行重置
- (void)recoveryByInitialResizeWHScale;
- (void)recoveryByInitialResizeWHScale:(BOOL)isToBeArbitrarily;

// 2.2 按當前裁剪寬高比進行重置(如果resizeWHScale為0,則重置到整個裁剪元素區(qū)域)
- (void)recoveryByCurrentResizeWHScale;
- (void)recoveryByCurrentResizeWHScale:(BOOL)isToBeArbitrarily;

// 2.3 按目標裁剪寬高比進行重置(如果resizeWHScale為0,則重置到整個裁剪元素區(qū)域)
// targetResizeWHScale:目標裁剪寬高比
// isToBeArbitrarily:重置之后 resizeWHScale 是否為任意比例(若為YES,最后 resizeWHScale = 0)
- (void)recoveryToTargetResizeWHScale:(CGFloat)targetResizeWHScale isToBeArbitrarily:(BOOL)isToBeArbitrarily;

3. 以圓切重置

- (void)recoveryToRoundResize;
- (void)recoveryToRoundResize:(BOOL)isToBeArbitrarily;

4. 以蒙版圖片重置

// 4.1 按當前蒙版圖片重置
- (void)recoveryByCurrentMaskImage;
- (void)recoveryByCurrentMaskImage:(BOOL)isToBeArbitrarily;

// 4.2 指定蒙版圖片重置
- (void)recoveryToMaskImage:(UIImage *)maskImage isToBeArbitrarily:(BOOL)isToBeArbitrarily;

預覽

// 預覽模式:隱藏邊框,停止拖拽操作,用于預覽裁剪后的區(qū)域

// 1.默認自帶動畫效果
self.imageresizerView.isPreview = YES;

// 2.自定義是否帶動畫效果
[self.imageresizerView setIsPreview:YES animated:NO]

保存當前裁剪狀態(tài)

// 1.很Easy,直接調(diào)用saveCurrentConfigure方法獲取當前裁剪的狀態(tài),可用一個全局變量來保存該對象
JPImageresizerConfigure *savedConfigure = [self.imageresizerView saveCurrentConfigure];

// 2.重新打開裁剪歷史
JPImageresizerView *imageresizerView = [JPImageresizerView imageresizerViewWithConfigure:savedConfigure imageresizerIsCanRecovery:^(BOOL isCanRecovery) {
    ......
} imageresizerIsPrepareToScale:^(BOOL isPrepareToScale) {
    ......
}];
[self.view addSubview:imageresizerView];
self.imageresizerView = imageresizerView;

// 3.可以設(shè)置JPImageresizerConfigure的isCleanHistoryAfterInitial屬性為YES,當初始化結(jié)束后自動清空歷史(默認為YES)
// 或者直接調(diào)用cleanHistory方法清空歷史
save
  • PS1:若保存的savedConfigure.history.viewFrame跟當前的viewFrame不一致,界面會導致錯亂,需要自行判斷是否一致才可重新打開;
  • PS2:另外目前只能在App使用期間進行保存,暫未實現(xiàn)持久化緩存。

其他

// 鎖定裁剪區(qū)域,鎖定后無法拖動裁剪區(qū)域,NO則解鎖
self.imageresizerView.isLockResizeFrame = YES;

// 旋轉(zhuǎn)至水平方向時是否自適應裁剪區(qū)域大小
// 當圖片寬度比圖片高度小時,該屬性默認YES,可手動設(shè)為NO
self.imageresizerView.isAutoScale = NO;

安裝

JPImageresizerView 可通過CocoaPods安裝,只需添加下面一行到你的podfile:

pod 'JPImageresizerView'

反饋地址

郵箱:zhoujianping24@hotmail.com
扣扣:184669029
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容