Files
midi_ios/TUIKit/TUIMultimediaPlugin/Edit/UI/PhotoEditor/TUIMultimediaPictureEditorController.m

287 lines
12 KiB
Mathematica
Raw Normal View History

2025-08-14 10:07:49 +08:00
// Copyright (c) 2024 Tencent. All rights reserved.
// Author: eddardliu
#import "TUIMultimediaPictureEditorController.h"
#import <ReactiveObjC/ReactiveObjC.h>
#import <Masonry/Masonry.h>
#import <TXLiteAVSDK_Professional/TXPictureEditer.h>
#import <TXLiteAVSDK_Professional/TXVideoEditerTypeDef.h>
#import "TUIMultimediaPlugin/NSArray+Functional.h"
#import "TUIMultimediaPlugin/TUIMultimediaCommonEditorControlView.h"
#import "TUIMultimediaPlugin/TUIMultimediaConstant.h"
#import "TUIMultimediaPlugin/TUIMultimediaPasterConfig.h"
#import "TUIMultimediaPlugin/TUIMultimediaPasterSelectController.h"
#import "TUIMultimediaPlugin/TUIMultimediaSubtitleEditController.h"
#import "TUIMultimediaPlugin/TUIMultimediaCommon.h"
#import "TUIMultimediaPlugin/TUIMultimediaSticker.h"
#import "TUIMultimediaPlugin/TUIMultimediaAuthorizationPrompter.h"
@interface TUIMultimediaPictureEditorController () <TUIMultimediaCommonEditorControlViewDelegate, TUIMultimediaPasterSelectControllerDelegate> {
TXPictureEditer *_editor;
UIImageView *_imgView;
TUIMultimediaPasterSelectController *_pasterSelectController;
TUIMultimediaSubtitleEditController *_subtitleEditController;
TUIMultimediaCommonEditorControlView *_commonEditCtrlView;
BOOL _originNavgationBarHidden;
BOOL _hasCrop;
}
@end
@implementation TUIMultimediaPictureEditorController
- (instancetype)init {
self = [super init];
_hasCrop = false;
_sourceType = SOURCE_TYPE_RECORD;
return self;
}
- (void)viewDidLoad {
_editor = [[TXPictureEditer alloc] init];
_pasterSelectController = [[TUIMultimediaPasterSelectController alloc] init];
_pasterSelectController.delegate = self;
_pasterSelectController.modalPresentationStyle = UIModalPresentationOverCurrentContext;
_subtitleEditController = [[TUIMultimediaSubtitleEditController alloc] init];
_subtitleEditController.modalPresentationStyle = UIModalPresentationOverCurrentContext;
_commonEditCtrlView = [[TUIMultimediaCommonEditorControlView alloc] initWithConfig:TUIMultimediaCommonEditorConfig.configForPictureEditor];
[self.view addSubview:_commonEditCtrlView];
_commonEditCtrlView.delegate = self;
_commonEditCtrlView.clipsToBounds = true;
_commonEditCtrlView.sourceType = _sourceType;
_commonEditCtrlView.frame = CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height);
_commonEditCtrlView.previewSize = _srcPicture.size;
_imgView = [[UIImageView alloc] init];
_imgView.image = _srcPicture;
[_commonEditCtrlView.previewView addSubview:_imgView];
[_imgView mas_makeConstraints:^(MASConstraintMaker *make) {
make.edges.equalTo(_commonEditCtrlView.previewView);
}];
_commonEditCtrlView.mosaciOriginalImage = _srcPicture;
UIPinchGestureRecognizer *pinchRec = [[UIPinchGestureRecognizer alloc] initWithTarget:self action:@selector(onPinch:)];
[self.view addGestureRecognizer:pinchRec];
UIPanGestureRecognizer *panGesture = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(onPanGesture:)];
[self.view addGestureRecognizer:panGesture];
}
- (void)onPinch:(UIPinchGestureRecognizer *)gestureRecognizer {
switch (gestureRecognizer.state) {
case UIGestureRecognizerStateChanged: {
if (gestureRecognizer.numberOfTouches < 2) {
break;
}
CGPoint touchPoint1 = [gestureRecognizer locationOfTouch:0 inView:self.view];
CGPoint touchPoint2 = [gestureRecognizer locationOfTouch:1 inView:self.view];
CGPoint scaleCenter = CGPointMake((touchPoint1.x + touchPoint2.x) / 2, (touchPoint1.y + touchPoint2.y) / 2);
[_commonEditCtrlView previewScale:gestureRecognizer.scale center:scaleCenter];
gestureRecognizer.scale = 1.0f;
break;
}
case UIGestureRecognizerStateEnded:
[_commonEditCtrlView previewAdjustToLimitRect];
break;
default:
break;
}
}
- (void)onPanGesture:(UIPanGestureRecognizer *)gestureRecognizer {
switch (gestureRecognizer.state) {
case UIGestureRecognizerStateChanged: {
CGPoint offset = [gestureRecognizer translationInView:self.view];
[gestureRecognizer setTranslation:CGPointZero inView:self.view];
[_commonEditCtrlView previewMove:offset];
break;
}
case UIGestureRecognizerStateEnded:
[_commonEditCtrlView previewAdjustToLimitRect];
break;
default:
break;
}
}
- (void)viewWillAppear:(BOOL)animated {
if (self.navigationController != nil) {
_originNavgationBarHidden = self.navigationController.navigationBarHidden;
self.navigationController.navigationBarHidden = YES;
}
}
- (void)viewWillDisappear:(BOOL)animated {
if (self.navigationController != nil) {
self.navigationController.navigationBarHidden = _originNavgationBarHidden;
}
}
#pragma mark - Properties
- (void)setSrcPicture:(UIImage *)photo {
_srcPicture = photo;
_imgView.image = _srcPicture;
_commonEditCtrlView.previewSize = _srcPicture.size;
}
- (void)setSourceType:(int)sourceType {
NSLog(@"setSourceType sourceType = %d",sourceType);
_sourceType = sourceType;
if (_commonEditCtrlView != nil) {
_commonEditCtrlView.sourceType = sourceType;
}
}
#pragma mark - TUIMultimediaCommonEditorControlViewDelegate protocol
- (void)onCommonEditorControlViewCancel:(nonnull TUIMultimediaCommonEditorControlView *)view {
if (_completeCallback == nil) {
return;
}
_completeCallback(nil, PHOTO_EDIT_RESULT_CODE_CANCEL);
}
- (void)onCommonEditorControlViewCancelGenerate:(nonnull TUIMultimediaCommonEditorControlView *)view {
}
- (void)onCommonEditorControlViewComplete:(nonnull TUIMultimediaCommonEditorControlView *)view
stickers:(nonnull NSArray<TUIMultimediaSticker *> *)stickers {
if (![TUIMultimediaAuthorizationPrompter verifyPermissionGranted:self]) {
return;
}
if (_completeCallback == nil) {
return;
}
if (stickers.count == 0) {
NSLog(@"Return directly without edit the picture");
UIImage* outputImage = (_hasCrop || _sourceType == SOURCE_TYPE_RECORD) ? _srcPicture : nil;
_completeCallback(outputImage, _hasCrop ? VIDEO_EDIT_RESULT_CODE_GENERATE_SUCCESS : VIDEO_EDIT_RESULT_CODE_NO_EDIT);
return;
}
[_editor setPicture:_srcPicture];
[_editor setOutputRotation:0];
[_editor setOutputSize:_srcPicture.size.width height:_srcPicture.size.height];
[_editor setPasterList:[self stickercConvertToPaster:stickers rotationAngle:0]];
@weakify(self)
[_editor processPicture:^(UIImage *processedPicture) {
@strongify(self)
self.completeCallback(processedPicture, PHOTO_EDIT_RESULT_CODE_GENERATE_SUCCESS);
}];
}
- (void)onCommonEditorControlViewCrop:(NSInteger)rotationAngle normalizedCropRect:(CGRect)normalizedCropRect
stickers:(NSArray<TUIMultimediaSticker *> *)stickers {
[_editor setPicture:_srcPicture];
[_editor setPasterList:[self stickercConvertToPaster:stickers rotationAngle:rotationAngle]];
normalizedCropRect = [self adjustCropRectAccordingRotaionAngle:normalizedCropRect rotationAngle:rotationAngle];
CGRect cropRect = CGRectMake(normalizedCropRect.origin.x * _srcPicture.size.width * _srcPicture.scale,
normalizedCropRect.origin.y * _srcPicture.size.height * _srcPicture.scale,
normalizedCropRect.size.width * _srcPicture.size.width * _srcPicture.scale,
normalizedCropRect.size.height * _srcPicture.size.height * _srcPicture.scale);
[_editor setCropRect:cropRect];
CGSize outputSize = [self getOutputSize:cropRect.size rotationAngle:rotationAngle];
[_editor setOutputSize:outputSize.width height:outputSize.height];
[_editor setOutputRotation:(CGFloat)rotationAngle];
[_editor processPicture:^(UIImage *processedPicture) {
[self onProcessPictureForCrop:processedPicture];
}];
}
- (CGSize) getOutputSize:(CGSize) cropRectSize rotationAngle:(CGFloat) rotationAngle {
int outputWidth = 1080;
int outputHeight = 1920;
if(((int)rotationAngle + 180) % 180 == 0) {
outputHeight = cropRectSize.height / cropRectSize.width * outputWidth;
} else {
outputHeight = cropRectSize.width / cropRectSize.height * outputWidth;
}
return CGSizeMake(outputWidth, outputHeight);
}
- (NSArray<TXPaster *> *) stickercConvertToPaster:(nonnull NSArray<TUIMultimediaSticker *> *)stickers rotationAngle:(NSInteger)rotationAngle {
CGSize previewSize = _commonEditCtrlView.previewView.frame.size;
return [stickers tui_multimedia_map:^TXPaster *(TUIMultimediaSticker *s) {
TXPaster *p = [[TXPaster alloc] init];
p.pasterImage = s.image;
CGRect frame = CGRectMake(s.frame.origin.x / previewSize.width,
s.frame.origin.y / previewSize.height,
s.frame.size.width / previewSize.width,
s.frame.size.height / previewSize.height);
p.frame = frame;
return p;
}];
}
- (CGRect) adjustCropRectAccordingRotaionAngle:(CGRect)normalizedCropRect rotationAngle:(CGFloat)rotationAngle {
normalizedCropRect = CGRectMake(MIN(1.0f, MAX(normalizedCropRect.origin.x, 0)),
MIN(1.0f, MAX(normalizedCropRect.origin.y, 0)),
MIN(1.0f, MAX(normalizedCropRect.size.width, 0)),
MIN(1.0f, MAX(normalizedCropRect.size.height, 0)));
if (rotationAngle == 90) {
normalizedCropRect = CGRectMake(normalizedCropRect.origin.y,
1 - normalizedCropRect.size.width - normalizedCropRect.origin.x,
normalizedCropRect.size.height,
normalizedCropRect.size.width);
} else if (rotationAngle == 180) {
normalizedCropRect = CGRectMake(1 - normalizedCropRect.size.width - normalizedCropRect.origin.x,
1 - normalizedCropRect.size.height - normalizedCropRect.origin.y,
normalizedCropRect.size.width,
normalizedCropRect.size.height);
} else if (rotationAngle == 270) {
normalizedCropRect = CGRectMake(1 - normalizedCropRect.origin.y - normalizedCropRect.size.height,
normalizedCropRect.origin.x,
normalizedCropRect.size.height,
normalizedCropRect.size.width);
}
return normalizedCropRect;
}
- (void) onProcessPictureForCrop:(UIImage *) processedPicture {
_hasCrop = true;
_srcPicture = processedPicture;
_commonEditCtrlView.previewView.hidden = NO;
_commonEditCtrlView.previewSize = _srcPicture.size;
_imgView.image = _srcPicture;
_commonEditCtrlView.mosaciOriginalImage = _srcPicture;
}
- (void)onCommonEditorControlViewNeedAddPaster:(TUIMultimediaCommonEditorControlView *)view {
_commonEditCtrlView.modifyButtonsHidden = YES;
[self presentViewController:_pasterSelectController animated:NO completion:nil];
}
- (void)onCommonEditorControlViewNeedModifySubtitle:(TUIMultimediaSubtitleInfo *)info callback:(void (^)(TUIMultimediaSubtitleInfo *info, BOOL isOk))callback {
_subtitleEditController.subtitleInfo = info;
_subtitleEditController.callback = ^(TUIMultimediaSubtitleEditController *c, BOOL isOk) {
[c.presentingViewController dismissViewControllerAnimated:NO completion:nil];
if (callback != nil) {
callback(c.subtitleInfo, isOk);
}
};
[self presentViewController:_subtitleEditController animated:NO completion:nil];
}
- (void)onCommonEditorControlViewNeedEditMusic:(nonnull TUIMultimediaCommonEditorControlView *)view {
}
#pragma mark - TUIMultimediaPasterSelectControllerDelegate protocol
- (void)pasterSelectController:(TUIMultimediaPasterSelectController *)c onPasterSelected:(UIImage *)image {
[_commonEditCtrlView addPaster:image];
_commonEditCtrlView.modifyButtonsHidden = NO;
[c.presentingViewController dismissViewControllerAnimated:NO completion:nil];
}
- (void)onPasterSelectControllerExit:(TUIMultimediaPasterSelectController *)c {
_commonEditCtrlView.modifyButtonsHidden = NO;
[c.presentingViewController dismissViewControllerAnimated:NO completion:nil];
}
@end