mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
Video editor fixes
This commit is contained in:
parent
9c9fd6cc03
commit
ef5756702c
@ -4,8 +4,6 @@
|
||||
|
||||
@interface PGPhotoEditorValues : NSObject <TGMediaEditAdjustments>
|
||||
|
||||
@property (nonatomic, readonly) CGFloat cropRotation;
|
||||
|
||||
+ (instancetype)editorValuesWithOriginalSize:(CGSize)originalSize cropRect:(CGRect)cropRect cropRotation:(CGFloat)cropRotation cropOrientation:(UIImageOrientation)cropOrientation cropLockedAspectRatio:(CGFloat)cropLockedAspectRatio cropMirrored:(bool)cropMirrored toolValues:(NSDictionary *)toolValues paintingData:(TGPaintingData *)paintingData sendAsGif:(bool)sendAsGif;
|
||||
|
||||
@end
|
||||
|
@ -25,6 +25,7 @@
|
||||
@property (nonatomic, readonly) CGSize originalSize;
|
||||
@property (nonatomic, readonly) CGRect cropRect;
|
||||
@property (nonatomic, readonly) UIImageOrientation cropOrientation;
|
||||
@property (nonatomic, readonly) CGFloat cropRotation;
|
||||
@property (nonatomic, readonly) CGFloat cropLockedAspectRatio;
|
||||
@property (nonatomic, readonly) bool cropMirrored;
|
||||
@property (nonatomic, readonly) bool sendAsGif;
|
||||
|
@ -20,7 +20,7 @@
|
||||
+ (SSignal *)convertAVAsset:(AVAsset *)avAsset adjustments:(TGMediaVideoEditAdjustments *)adjustments watcher:(TGMediaVideoFileWatcher *)watcher inhibitAudio:(bool)inhibitAudio entityRenderer:(id<TGPhotoPaintEntityRenderer>)entityRenderer;
|
||||
+ (SSignal *)hashForAVAsset:(AVAsset *)avAsset adjustments:(TGMediaVideoEditAdjustments *)adjustments;
|
||||
|
||||
+ (SSignal *)renderUIImage:(UIImage *)image adjustments:(TGMediaVideoEditAdjustments *)adjustments watcher:(TGMediaVideoFileWatcher *)watcher entityRenderer:(id<TGPhotoPaintEntityRenderer>)entityRenderer;
|
||||
+ (SSignal *)renderUIImage:(UIImage *)image duration:(NSTimeInterval)duration adjustments:(TGMediaVideoEditAdjustments *)adjustments watcher:(TGMediaVideoFileWatcher *)watcher entityRenderer:(id<TGPhotoPaintEntityRenderer>)entityRenderer;
|
||||
|
||||
+ (NSUInteger)estimatedSizeForPreset:(TGMediaVideoConversionPreset)preset duration:(NSTimeInterval)duration hasAudio:(bool)hasAudio;
|
||||
+ (TGMediaVideoConversionPreset)bestAvailablePresetForDimensions:(CGSize)dimensions;
|
||||
|
@ -26,6 +26,8 @@
|
||||
|
||||
+ (instancetype)dataWithPaintingImagePath:(NSString *)imagePath;
|
||||
|
||||
- (instancetype)dataForAnimation;
|
||||
|
||||
+ (void)storePaintingData:(TGPaintingData *)data inContext:(TGMediaEditingContext *)context forItem:(id<TGMediaEditableItem>)item forVideo:(bool)video;
|
||||
+ (void)facilitatePaintingData:(TGPaintingData *)data;
|
||||
|
||||
|
@ -14,6 +14,7 @@ CGFloat TGRadiansToDegrees(CGFloat radians);
|
||||
|
||||
UIImage *TGPhotoEditorCrop(UIImage *image, UIImage *paintingImage, UIImageOrientation orientation, CGFloat rotation, CGRect rect, bool mirrored, CGSize maxSize, CGSize originalSize, bool shouldResize);
|
||||
UIImage *TGPhotoEditorVideoCrop(UIImage *image, UIImage *paintingImage, UIImageOrientation orientation, CGFloat rotation, CGRect rect, bool mirrored, CGSize maxSize, CGSize originalSize, bool shouldResize, bool useImageSize);
|
||||
UIImage *TGPhotoEditorVideoExtCrop(UIImage *inputImage, UIImage *paintingImage, UIImageOrientation orientation, CGFloat rotation, CGRect rect, bool mirrored, CGSize maxSize, CGSize originalSize, bool shouldResize, bool useImageSize, bool skipImageTransform);
|
||||
UIImage *TGPhotoEditorFitImage(UIImage *image, CGSize maxSize);
|
||||
CGSize TGRotatedContentSize(CGSize contentSize, CGFloat rotation);
|
||||
|
||||
|
@ -18,6 +18,13 @@
|
||||
|
||||
@end
|
||||
|
||||
@protocol TGPhotoPaintStickersScreen <NSObject>
|
||||
|
||||
- (void)restore;
|
||||
- (void)invalidate;
|
||||
|
||||
@end
|
||||
|
||||
@protocol TGPhotoPaintStickersContext <NSObject>
|
||||
|
||||
- (int64_t)documentIdForDocument:(id)document;
|
||||
@ -25,6 +32,6 @@
|
||||
|
||||
- (UIView<TGPhotoPaintStickerRenderView> *)stickerViewForDocument:(id)document;
|
||||
|
||||
@property (nonatomic, copy) void(^presentStickersController)(void(^)(id, bool, UIView *, CGRect));
|
||||
@property (nonatomic, copy) id<TGPhotoPaintStickersScreen>(^presentStickersController)(void(^)(id, bool, UIView *, CGRect));
|
||||
|
||||
@end
|
||||
|
@ -37,6 +37,7 @@ typedef enum
|
||||
+ (instancetype)editAdjustmentsWithOriginalSize:(CGSize)originalSize
|
||||
cropRect:(CGRect)cropRect
|
||||
cropOrientation:(UIImageOrientation)cropOrientation
|
||||
cropRotation:(CGFloat)cropRotation
|
||||
cropLockedAspectRatio:(CGFloat)cropLockedAspectRatio
|
||||
cropMirrored:(bool)cropMirrored
|
||||
trimStartValue:(NSTimeInterval)trimStartValue
|
||||
|
15
submodules/LegacyComponents/Sources/GPUImageCropFilter.h
Executable file
15
submodules/LegacyComponents/Sources/GPUImageCropFilter.h
Executable file
@ -0,0 +1,15 @@
|
||||
#import "GPUImageFilter.h"
|
||||
|
||||
@interface GPUImageCropFilter : GPUImageFilter
|
||||
{
|
||||
GLfloat cropTextureCoordinates[8];
|
||||
}
|
||||
|
||||
// The crop region is the rectangle within the image to crop. It is normalized to a coordinate space from 0.0 to 1.0, with 0.0, 0.0 being the upper left corner of the image
|
||||
@property(readwrite, nonatomic) CGRect cropRegion;
|
||||
@property(readwrite, nonatomic) GPUImageRotationMode rotationMode;
|
||||
|
||||
// Initialization and teardown
|
||||
- (id)initWithCropRegion:(CGRect)newCropRegion;
|
||||
|
||||
@end
|
248
submodules/LegacyComponents/Sources/GPUImageCropFilter.m
Executable file
248
submodules/LegacyComponents/Sources/GPUImageCropFilter.m
Executable file
@ -0,0 +1,248 @@
|
||||
#import "GPUImageCropFilter.h"
|
||||
|
||||
|
||||
NSString *const kGPUImageCropFragmentShaderString = SHADER_STRING
|
||||
(
|
||||
varying highp vec2 texCoord;
|
||||
|
||||
uniform sampler2D sourceImage;
|
||||
|
||||
void main()
|
||||
{
|
||||
gl_FragColor = texture2D(sourceImage, texCoord);
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
@interface GPUImageCropFilter ()
|
||||
|
||||
- (void)calculateCropTextureCoordinates;
|
||||
|
||||
@end
|
||||
|
||||
@interface GPUImageCropFilter()
|
||||
{
|
||||
CGSize originallySuppliedInputSize;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation GPUImageCropFilter
|
||||
|
||||
@synthesize cropRegion = _cropRegion;
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Initialization and teardown
|
||||
|
||||
- (id)initWithCropRegion:(CGRect)newCropRegion;
|
||||
{
|
||||
if (!(self = [super initWithFragmentShaderFromString:kGPUImageCropFragmentShaderString]))
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
|
||||
self.cropRegion = newCropRegion;
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (id)init;
|
||||
{
|
||||
if (!(self = [self initWithCropRegion:CGRectMake(0.0, 0.0, 1.0, 1.0)]))
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Rendering
|
||||
|
||||
- (void)setInputSize:(CGSize)newSize atIndex:(NSInteger)textureIndex;
|
||||
{
|
||||
if (self.preventRendering)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
CGSize rotatedSize = [self rotatedSize:newSize forIndex:textureIndex];
|
||||
originallySuppliedInputSize = rotatedSize;
|
||||
|
||||
CGSize scaledSize;
|
||||
scaledSize.width = rotatedSize.width * _cropRegion.size.width;
|
||||
scaledSize.height = rotatedSize.height * _cropRegion.size.height;
|
||||
|
||||
|
||||
if (CGSizeEqualToSize(scaledSize, CGSizeZero))
|
||||
{
|
||||
inputTextureSize = scaledSize;
|
||||
}
|
||||
else if (!CGSizeEqualToSize(inputTextureSize, scaledSize))
|
||||
{
|
||||
inputTextureSize = scaledSize;
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark GPUImageInput
|
||||
|
||||
- (void)calculateCropTextureCoordinates;
|
||||
{
|
||||
CGFloat minX = _cropRegion.origin.x;
|
||||
CGFloat minY = _cropRegion.origin.y;
|
||||
CGFloat maxX = CGRectGetMaxX(_cropRegion);
|
||||
CGFloat maxY = CGRectGetMaxY(_cropRegion);
|
||||
|
||||
switch(inputRotation)
|
||||
{
|
||||
case kGPUImageNoRotation: // Works
|
||||
{
|
||||
cropTextureCoordinates[0] = minX; // 0,0
|
||||
cropTextureCoordinates[1] = minY;
|
||||
|
||||
cropTextureCoordinates[2] = maxX; // 1,0
|
||||
cropTextureCoordinates[3] = minY;
|
||||
|
||||
cropTextureCoordinates[4] = minX; // 0,1
|
||||
cropTextureCoordinates[5] = maxY;
|
||||
|
||||
cropTextureCoordinates[6] = maxX; // 1,1
|
||||
cropTextureCoordinates[7] = maxY;
|
||||
}; break;
|
||||
case kGPUImageRotateLeft: // Fixed
|
||||
{
|
||||
cropTextureCoordinates[0] = maxY; // 1,0
|
||||
cropTextureCoordinates[1] = 1.0 - maxX;
|
||||
|
||||
cropTextureCoordinates[2] = maxY; // 1,1
|
||||
cropTextureCoordinates[3] = 1.0 - minX;
|
||||
|
||||
cropTextureCoordinates[4] = minY; // 0,0
|
||||
cropTextureCoordinates[5] = 1.0 - maxX;
|
||||
|
||||
cropTextureCoordinates[6] = minY; // 0,1
|
||||
cropTextureCoordinates[7] = 1.0 - minX;
|
||||
}; break;
|
||||
case kGPUImageRotateRight: // Fixed
|
||||
{
|
||||
cropTextureCoordinates[0] = minY; // 0,1
|
||||
cropTextureCoordinates[1] = 1.0 - minX;
|
||||
|
||||
cropTextureCoordinates[2] = minY; // 0,0
|
||||
cropTextureCoordinates[3] = 1.0 - maxX;
|
||||
|
||||
cropTextureCoordinates[4] = maxY; // 1,1
|
||||
cropTextureCoordinates[5] = 1.0 - minX;
|
||||
|
||||
cropTextureCoordinates[6] = maxY; // 1,0
|
||||
cropTextureCoordinates[7] = 1.0 - maxX;
|
||||
}; break;
|
||||
case kGPUImageFlipVertical: // Works for me
|
||||
{
|
||||
cropTextureCoordinates[0] = minX; // 0,1
|
||||
cropTextureCoordinates[1] = maxY;
|
||||
|
||||
cropTextureCoordinates[2] = maxX; // 1,1
|
||||
cropTextureCoordinates[3] = maxY;
|
||||
|
||||
cropTextureCoordinates[4] = minX; // 0,0
|
||||
cropTextureCoordinates[5] = minY;
|
||||
|
||||
cropTextureCoordinates[6] = maxX; // 1,0
|
||||
cropTextureCoordinates[7] = minY;
|
||||
}; break;
|
||||
case kGPUImageFlipHorizonal: // Works for me
|
||||
{
|
||||
cropTextureCoordinates[0] = maxX; // 1,0
|
||||
cropTextureCoordinates[1] = minY;
|
||||
|
||||
cropTextureCoordinates[2] = minX; // 0,0
|
||||
cropTextureCoordinates[3] = minY;
|
||||
|
||||
cropTextureCoordinates[4] = maxX; // 1,1
|
||||
cropTextureCoordinates[5] = maxY;
|
||||
|
||||
cropTextureCoordinates[6] = minX; // 0,1
|
||||
cropTextureCoordinates[7] = maxY;
|
||||
}; break;
|
||||
case kGPUImageRotate180: // Fixed
|
||||
{
|
||||
cropTextureCoordinates[0] = maxX; // 1,1
|
||||
cropTextureCoordinates[1] = maxY;
|
||||
|
||||
cropTextureCoordinates[2] = minX; // 0,1
|
||||
cropTextureCoordinates[3] = maxY;
|
||||
|
||||
cropTextureCoordinates[4] = maxX; // 1,0
|
||||
cropTextureCoordinates[5] = minY;
|
||||
|
||||
cropTextureCoordinates[6] = minX; // 0,0
|
||||
cropTextureCoordinates[7] = minY;
|
||||
}; break;
|
||||
case kGPUImageRotateRightFlipVertical: // Fixed
|
||||
{
|
||||
cropTextureCoordinates[0] = minY; // 0,0
|
||||
cropTextureCoordinates[1] = 1.0 - maxX;
|
||||
|
||||
cropTextureCoordinates[2] = minY; // 0,1
|
||||
cropTextureCoordinates[3] = 1.0 - minX;
|
||||
|
||||
cropTextureCoordinates[4] = maxY; // 1,0
|
||||
cropTextureCoordinates[5] = 1.0 - maxX;
|
||||
|
||||
cropTextureCoordinates[6] = maxY; // 1,1
|
||||
cropTextureCoordinates[7] = 1.0 - minX;
|
||||
}; break;
|
||||
case kGPUImageRotateRightFlipHorizontal: // Fixed
|
||||
{
|
||||
cropTextureCoordinates[0] = maxY; // 1,1
|
||||
cropTextureCoordinates[1] = 1.0 - minX;
|
||||
|
||||
cropTextureCoordinates[2] = maxY; // 1,0
|
||||
cropTextureCoordinates[3] = 1.0 - maxX;
|
||||
|
||||
cropTextureCoordinates[4] = minY; // 0,1
|
||||
cropTextureCoordinates[5] = 1.0 - minX;
|
||||
|
||||
cropTextureCoordinates[6] = minY; // 0,0
|
||||
cropTextureCoordinates[7] = 1.0 - maxX;
|
||||
}; break;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)newFrameReadyAtTime:(CMTime)frameTime atIndex:(NSInteger)textureIndex;
|
||||
{
|
||||
static const GLfloat cropSquareVertices[] = {
|
||||
-1.0f, -1.0f,
|
||||
1.0f, -1.0f,
|
||||
-1.0f, 1.0f,
|
||||
1.0f, 1.0f,
|
||||
};
|
||||
|
||||
[self renderToTextureWithVertices:cropSquareVertices textureCoordinates:cropTextureCoordinates];
|
||||
|
||||
[self informTargetsAboutNewFrameAtTime:frameTime];
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Accessors
|
||||
|
||||
- (void)setCropRegion:(CGRect)newValue;
|
||||
{
|
||||
NSParameterAssert(newValue.origin.x >= 0 && newValue.origin.x <= 1 &&
|
||||
newValue.origin.y >= 0 && newValue.origin.y <= 1 &&
|
||||
newValue.size.width >= 0 && newValue.size.width <= 1 &&
|
||||
newValue.size.height >= 0 && newValue.size.height <= 1);
|
||||
|
||||
_cropRegion = newValue;
|
||||
[self calculateCropTextureCoordinates];
|
||||
}
|
||||
|
||||
- (void)setInputRotation:(GPUImageRotationMode)newInputRotation atIndex:(NSInteger)textureIndex;
|
||||
{
|
||||
[super setInputRotation:newInputRotation atIndex:textureIndex];
|
||||
[self calculateCropTextureCoordinates];
|
||||
}
|
||||
|
||||
@end
|
@ -18,8 +18,6 @@ NSString *const kGPUImageVertexShaderString = SHADER_STRING
|
||||
}
|
||||
);
|
||||
|
||||
#if TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE
|
||||
|
||||
NSString *const kGPUImagePassthroughFragmentShaderString = SHADER_STRING
|
||||
(
|
||||
varying highp vec2 texCoord;
|
||||
@ -32,21 +30,6 @@ NSString *const kGPUImagePassthroughFragmentShaderString = SHADER_STRING
|
||||
}
|
||||
);
|
||||
|
||||
#else
|
||||
|
||||
NSString *const kGPUImagePassthroughFragmentShaderString = SHADER_STRING
|
||||
(
|
||||
varying vec2 texCoord;
|
||||
|
||||
uniform sampler2D sourceImage;
|
||||
|
||||
void main()
|
||||
{
|
||||
gl_FragColor = texture2D(sourceImage, texCoord);
|
||||
}
|
||||
);
|
||||
#endif
|
||||
|
||||
|
||||
@implementation GPUImageFilter
|
||||
|
||||
|
@ -40,7 +40,7 @@
|
||||
- (void)cleanup;
|
||||
|
||||
- (void)setImage:(UIImage *)image forCropRect:(CGRect)cropRect cropRotation:(CGFloat)cropRotation cropOrientation:(UIImageOrientation)cropOrientation cropMirrored:(bool)cropMirrored fullSize:(bool)fullSize;
|
||||
- (void)setPlayerItem:(AVPlayerItem *)playerItem;
|
||||
- (void)setPlayerItem:(AVPlayerItem *)playerItem forCropRect:(CGRect)cropRect cropRotation:(CGFloat)cropRotation cropOrientation:(UIImageOrientation)cropOrientation cropMirrored:(bool)cropMirrored;
|
||||
- (void)setCIImage:(CIImage *)ciImage;
|
||||
|
||||
- (void)processAnimated:(bool)animated completion:(void (^)(void))completion;
|
||||
|
@ -11,6 +11,7 @@
|
||||
#import "PGPhotoEditorPicture.h"
|
||||
|
||||
#import "GPUImageTextureInput.h"
|
||||
#import "GPUImageCropFilter.h"
|
||||
|
||||
#import <LegacyComponents/PGPhotoEditorValues.h>
|
||||
#import <LegacyComponents/TGVideoEditAdjustments.h>
|
||||
@ -43,6 +44,9 @@
|
||||
id<TGMediaEditAdjustments> _initialAdjustments;
|
||||
|
||||
GPUImageOutput *_currentInput;
|
||||
GPUImageCropFilter *_cropFilter;
|
||||
GPUImageRotationMode _rotationMode;
|
||||
|
||||
NSArray *_currentProcessChain;
|
||||
GPUImageOutput <GPUImageInput> *_finalFilter;
|
||||
|
||||
@ -159,7 +163,7 @@
|
||||
_fullSize = fullSize;
|
||||
}
|
||||
|
||||
- (void)setPlayerItem:(AVPlayerItem *)playerItem {
|
||||
- (void)setPlayerItem:(AVPlayerItem *)playerItem forCropRect:(CGRect)cropRect cropRotation:(CGFloat)cropRotation cropOrientation:(UIImageOrientation)cropOrientation cropMirrored:(bool)cropMirrored {
|
||||
[_toolComposer invalidate];
|
||||
_currentProcessChain = nil;
|
||||
|
||||
@ -167,6 +171,36 @@
|
||||
PGVideoMovie *movie = [[PGVideoMovie alloc] initWithPlayerItem:playerItem];
|
||||
_currentInput = movie;
|
||||
|
||||
bool hasCropping = !CGPointEqualToPoint(cropRect.origin, CGPointZero) || (!CGSizeEqualToSize(cropRect.size, CGSizeZero) && !CGSizeEqualToSize(cropRect.size, _originalSize));
|
||||
|
||||
_rotationMode = kGPUImageNoRotation;
|
||||
if (cropOrientation != UIImageOrientationUp || cropMirrored || hasCropping) {
|
||||
CGRect normalizedCropRect = CGRectMake(0.0f, 0.0f, 1.0f, 1.0f);
|
||||
if (hasCropping) {
|
||||
normalizedCropRect = CGRectMake(cropRect.origin.x / _originalSize.width, cropRect.origin.y / _originalSize.height, cropRect.size.width / _originalSize.width, cropRect.size.height / _originalSize.height);
|
||||
}
|
||||
_cropFilter = [[GPUImageCropFilter alloc] initWithCropRegion:normalizedCropRect];
|
||||
if (cropOrientation != UIImageOrientationUp || cropMirrored) {
|
||||
switch (cropOrientation) {
|
||||
case UIImageOrientationLeft:
|
||||
_rotationMode = kGPUImageRotateLeft;
|
||||
break;
|
||||
case UIImageOrientationRight:
|
||||
_rotationMode = cropMirrored ? kGPUImageRotateRightFlipHorizontal : kGPUImageRotateRight;
|
||||
break;
|
||||
case UIImageOrientationDown:
|
||||
_rotationMode = kGPUImageRotate180;
|
||||
break;
|
||||
case UIImageOrientationUp:
|
||||
if (cropMirrored)
|
||||
_rotationMode = kGPUImageFlipHorizonal;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_fullSize = true;
|
||||
}
|
||||
|
||||
@ -341,7 +375,12 @@
|
||||
_currentProcessChain = processChain;
|
||||
|
||||
GPUImageOutput <GPUImageInput> *lastFilter = ((PGPhotoProcessPass *)_currentProcessChain.firstObject).filter;
|
||||
[_currentInput addTarget:lastFilter];
|
||||
if (_cropFilter != nil) {
|
||||
[_currentInput addTarget:_cropFilter];
|
||||
[_cropFilter addTarget:lastFilter];
|
||||
} else {
|
||||
[_currentInput addTarget:lastFilter];
|
||||
}
|
||||
|
||||
NSInteger chainLength = _currentProcessChain.count;
|
||||
if (chainLength > 1)
|
||||
@ -460,7 +499,7 @@
|
||||
{
|
||||
TGVideoEditAdjustments *initialAdjustments = (TGVideoEditAdjustments *)_initialAdjustments;
|
||||
|
||||
return [TGVideoEditAdjustments editAdjustmentsWithOriginalSize:self.originalSize cropRect:self.cropRect cropOrientation:self.cropOrientation cropLockedAspectRatio:self.cropLockedAspectRatio cropMirrored:self.cropMirrored trimStartValue:initialAdjustments.trimStartValue trimEndValue:initialAdjustments.trimEndValue toolValues:toolValues paintingData:paintingData sendAsGif:self.sendAsGif preset:self.preset];
|
||||
return [TGVideoEditAdjustments editAdjustmentsWithOriginalSize:self.originalSize cropRect:self.cropRect cropOrientation:self.cropOrientation cropRotation:self.cropRotation cropLockedAspectRatio:self.cropLockedAspectRatio cropMirrored:self.cropMirrored trimStartValue:initialAdjustments.trimStartValue trimEndValue:initialAdjustments.trimEndValue toolValues:toolValues paintingData:paintingData sendAsGif:self.sendAsGif preset:self.preset];
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -8,6 +8,7 @@
|
||||
@synthesize originalSize = _originalSize;
|
||||
@synthesize cropRect = _cropRect;
|
||||
@synthesize cropOrientation = _cropOrientation;
|
||||
@synthesize cropRotation = _cropRotation;
|
||||
@synthesize cropLockedAspectRatio = _cropLockedAspectRatio;
|
||||
@synthesize cropMirrored = _cropMirrored;
|
||||
@synthesize paintingData = _paintingData;
|
||||
|
@ -850,19 +850,14 @@
|
||||
NSData *data = UIImageJPEGRepresentation(image, 0.8);
|
||||
[data writeToFile:filePath atomically:true];
|
||||
dict[@"url"] = [NSURL fileURLWithPath:filePath];
|
||||
|
||||
|
||||
|
||||
if ([adjustments cropAppliedForAvatar:false] || adjustments.hasPainting || adjustments.toolsApplied)
|
||||
{
|
||||
CGRect scaledCropRect = CGRectMake(adjustments.cropRect.origin.x * image.size.width / adjustments.originalSize.width, adjustments.cropRect.origin.y * image.size.height / adjustments.originalSize.height, adjustments.cropRect.size.width * image.size.width / adjustments.originalSize.width, adjustments.cropRect.size.height * image.size.height / adjustments.originalSize.height);
|
||||
UIImage *paintingImage = adjustments.paintingData.stillImage;
|
||||
if (paintingImage == nil) {
|
||||
paintingImage = adjustments.paintingData.image;
|
||||
}
|
||||
if (adjustments.toolsApplied) {
|
||||
image = [PGPhotoEditor resultImageForImage:image adjustments:adjustments];
|
||||
}
|
||||
UIImage *thumbnailImage = TGPhotoEditorVideoCrop(image, paintingImage, adjustments.cropOrientation, 0, adjustments.cropRect, adjustments.cropMirrored, TGScaleToFill(asset.dimensions, CGSizeMake(384, 384)), adjustments.originalSize, true, true);
|
||||
UIImage *thumbnailImage = TGPhotoEditorVideoExtCrop(image, paintingImage, adjustments.cropOrientation, adjustments.cropRotation, adjustments.cropRect, adjustments.cropMirrored, TGScaleToFill(asset.dimensions, CGSizeMake(384, 384)), adjustments.originalSize, true, true, true);
|
||||
if (thumbnailImage != nil) {
|
||||
dict[@"previewImage"] = thumbnailImage;
|
||||
}
|
||||
|
@ -647,7 +647,9 @@
|
||||
[_paintingImageCache setImage:image forKey:itemId attributes:NULL];
|
||||
|
||||
NSData *imageData = UIImagePNGRepresentation(image);
|
||||
[[NSFileManager defaultManager] removeItemAtURL:imageUrl error:nil];
|
||||
bool imageSuccess = [imageData writeToURL:imageUrl options:NSDataWritingAtomic error:nil];
|
||||
[[NSFileManager defaultManager] removeItemAtURL:dataUrl error:nil];
|
||||
bool dataSuccess = [data writeToURL:dataUrl options:NSDataWritingAtomic error:nil];
|
||||
|
||||
if (imageSuccess && imageOutUrl != NULL)
|
||||
@ -664,6 +666,7 @@
|
||||
[_stillPaintingImageCache setImage:stillImage forKey:itemId attributes:NULL];
|
||||
|
||||
NSData *stillImageData = UIImagePNGRepresentation(stillImage);
|
||||
[[NSFileManager defaultManager] removeItemAtURL:stillImageUrl error:nil];
|
||||
[stillImageData writeToURL:stillImageUrl options:NSDataWritingAtomic error:nil];
|
||||
|
||||
if (video)
|
||||
|
@ -1108,7 +1108,7 @@
|
||||
|
||||
strongSelf->_photoEditor = [[PGPhotoEditor alloc] initWithOriginalSize:strongSelf->_videoDimensions adjustments:adjustments forVideo:true enableStickers:true];
|
||||
strongSelf->_photoEditor.previewOutput = strongSelf->_videoView;
|
||||
[strongSelf->_photoEditor setPlayerItem:playerItem];
|
||||
[strongSelf->_photoEditor setPlayerItem:playerItem forCropRect:CGRectZero cropRotation:0.0 cropOrientation:UIImageOrientationUp cropMirrored:false];
|
||||
[strongSelf->_photoEditor processAnimated:false completion:nil];
|
||||
|
||||
[strongSelf _seekToPosition:adjustments.trimStartValue manual:false];
|
||||
@ -1383,7 +1383,7 @@
|
||||
[self updatePlayerRange:trimEndValue];
|
||||
}
|
||||
|
||||
TGVideoEditAdjustments *updatedAdjustments = [TGVideoEditAdjustments editAdjustmentsWithOriginalSize:_videoDimensions cropRect:cropRect cropOrientation:adjustments.cropOrientation cropLockedAspectRatio:adjustments.cropLockedAspectRatio cropMirrored:adjustments.cropMirrored trimStartValue:trimStartValue trimEndValue:trimEndValue toolValues:adjustments.toolValues paintingData:adjustments.paintingData sendAsGif:sendAsGif preset:adjustments.preset];
|
||||
TGVideoEditAdjustments *updatedAdjustments = [TGVideoEditAdjustments editAdjustmentsWithOriginalSize:_videoDimensions cropRect:cropRect cropOrientation:adjustments.cropOrientation cropRotation:adjustments.cropRotation cropLockedAspectRatio:adjustments.cropLockedAspectRatio cropMirrored:adjustments.cropMirrored trimStartValue:trimStartValue trimEndValue:trimEndValue toolValues:adjustments.toolValues paintingData:adjustments.paintingData sendAsGif:sendAsGif preset:adjustments.preset];
|
||||
[self.item.editingContext setAdjustments:updatedAdjustments forItem:self.item.editableMediaItem];
|
||||
|
||||
if (sendAsGif)
|
||||
@ -1475,7 +1475,7 @@
|
||||
UIImageOrientation cropOrientation = (adjustments != nil) ? adjustments.cropOrientation : UIImageOrientationUp;
|
||||
CGFloat cropLockedAspectRatio = (adjustments != nil) ? adjustments.cropLockedAspectRatio : 0.0f;
|
||||
|
||||
TGVideoEditAdjustments *updatedAdjustments = [TGVideoEditAdjustments editAdjustmentsWithOriginalSize:_videoDimensions cropRect:cropRect cropOrientation:cropOrientation cropLockedAspectRatio:cropLockedAspectRatio cropMirrored:adjustments.cropMirrored trimStartValue:_scrubberView.trimStartValue trimEndValue:_scrubberView.trimEndValue toolValues:adjustments.toolValues paintingData:adjustments.paintingData sendAsGif:adjustments.sendAsGif preset:adjustments.preset];
|
||||
TGVideoEditAdjustments *updatedAdjustments = [TGVideoEditAdjustments editAdjustmentsWithOriginalSize:_videoDimensions cropRect:cropRect cropOrientation:cropOrientation cropRotation:adjustments.cropRotation cropLockedAspectRatio:cropLockedAspectRatio cropMirrored:adjustments.cropMirrored trimStartValue:_scrubberView.trimStartValue trimEndValue:_scrubberView.trimEndValue toolValues:adjustments.toolValues paintingData:adjustments.paintingData sendAsGif:adjustments.sendAsGif preset:adjustments.preset];
|
||||
|
||||
[self.item.editingContext setAdjustments:updatedAdjustments forItem:self.item.editableMediaItem];
|
||||
}
|
||||
|
@ -154,7 +154,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
if (![self setupAssetReaderWriterForAVAsset:avAsset image:nil outputURL:outputUrl preset:preset entityRenderer:entityRenderer adjustments:adjustments inhibitAudio:inhibitAudio conversionContext:context error:&error])
|
||||
if (![self setupAssetReaderWriterForAVAsset:avAsset image:nil duration:0.0 outputURL:outputUrl preset:preset entityRenderer:entityRenderer adjustments:adjustments inhibitAudio:inhibitAudio conversionContext:context error:&error])
|
||||
{
|
||||
[subscriber putError:error];
|
||||
return;
|
||||
@ -212,7 +212,7 @@
|
||||
}];
|
||||
}
|
||||
|
||||
+ (SSignal *)renderUIImage:(UIImage *)image adjustments:(TGMediaVideoEditAdjustments *)adjustments watcher:(TGMediaVideoFileWatcher *)watcher entityRenderer:(id<TGPhotoPaintEntityRenderer>)entityRenderer
|
||||
+ (SSignal *)renderUIImage:(UIImage *)image duration:(NSTimeInterval)duration adjustments:(TGMediaVideoEditAdjustments *)adjustments watcher:(TGMediaVideoFileWatcher *)watcher entityRenderer:(id<TGPhotoPaintEntityRenderer>)entityRenderer
|
||||
{
|
||||
SQueue *queue = [[SQueue alloc] init];
|
||||
|
||||
@ -248,7 +248,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
if (![self setupAssetReaderWriterForAVAsset:avAsset image:image outputURL:outputUrl preset:preset entityRenderer:entityRenderer adjustments:adjustments inhibitAudio:true conversionContext:context error:&error])
|
||||
if (![self setupAssetReaderWriterForAVAsset:avAsset image:image duration:duration outputURL:outputUrl preset:preset entityRenderer:entityRenderer adjustments:adjustments inhibitAudio:true conversionContext:context error:&error])
|
||||
{
|
||||
[subscriber putError:error];
|
||||
return;
|
||||
@ -350,18 +350,7 @@
|
||||
UIImage *overlayImage = nil;
|
||||
if (adjustments.paintingData.imagePath != nil)
|
||||
overlayImage = [UIImage imageWithContentsOfFile:adjustments.paintingData.imagePath];
|
||||
|
||||
bool hasAnimation = false;
|
||||
for (TGPhotoPaintEntity *entity in adjustments.paintingData.entities) {
|
||||
if (entity.animated) {
|
||||
hasAnimation = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!hasAnimation) {
|
||||
entityRenderer = nil;
|
||||
}
|
||||
|
||||
|
||||
AVMutableVideoComposition *videoComposition;
|
||||
if (entityRenderer != nil || adjustments.toolsApplied) {
|
||||
PGPhotoEditor *editor = nil;
|
||||
@ -504,7 +493,7 @@
|
||||
return output;
|
||||
}
|
||||
|
||||
+ (bool)setupAssetReaderWriterForAVAsset:(AVAsset *)avAsset image:(UIImage *)image outputURL:(NSURL *)outputURL preset:(TGMediaVideoConversionPreset)preset entityRenderer:(id<TGPhotoPaintEntityRenderer>)entityRenderer adjustments:(TGMediaVideoEditAdjustments *)adjustments inhibitAudio:(bool)inhibitAudio conversionContext:(SAtomic *)outConversionContext error:(NSError **)error
|
||||
+ (bool)setupAssetReaderWriterForAVAsset:(AVAsset *)avAsset image:(UIImage *)image duration:(NSTimeInterval)duration outputURL:(NSURL *)outputURL preset:(TGMediaVideoConversionPreset)preset entityRenderer:(id<TGPhotoPaintEntityRenderer>)entityRenderer adjustments:(TGMediaVideoEditAdjustments *)adjustments inhibitAudio:(bool)inhibitAudio conversionContext:(SAtomic *)outConversionContext error:(NSError **)error
|
||||
{
|
||||
if (image == nil) {
|
||||
TGMediaSampleBufferProcessor *videoProcessor = nil;
|
||||
@ -579,7 +568,7 @@
|
||||
|
||||
CGSize dimensions = CGSizeZero;
|
||||
NSDictionary *outputSettings = nil;
|
||||
CMTimeRange timeRange = CMTimeRangeMake(CMTimeMakeWithSeconds(0.0, NSEC_PER_SEC), CMTimeMakeWithSeconds(3.0, NSEC_PER_SEC));
|
||||
CMTimeRange timeRange = CMTimeRangeMake(CMTimeMakeWithSeconds(0.0, NSEC_PER_SEC), CMTimeMakeWithSeconds(duration, NSEC_PER_SEC));
|
||||
AVMutableComposition *composition = [AVMutableComposition composition];
|
||||
|
||||
AVAssetTrack *videoTrack = [[avAsset tracksWithMediaType:AVMediaTypeVideo] firstObject];
|
||||
|
@ -46,6 +46,13 @@
|
||||
return paintingData;
|
||||
}
|
||||
|
||||
- (instancetype)dataForAnimation
|
||||
{
|
||||
TGPaintingData *paintingData = [[TGPaintingData alloc] init];
|
||||
paintingData->_entities = _entities;
|
||||
return paintingData;
|
||||
}
|
||||
|
||||
+ (void)storePaintingData:(TGPaintingData *)data inContext:(TGMediaEditingContext *)context forItem:(id<TGMediaEditableItem>)item forVideo:(bool)video
|
||||
{
|
||||
[[TGPaintingData queue] dispatch:^
|
||||
|
@ -406,7 +406,7 @@
|
||||
_player.actionAtItemEnd = AVPlayerActionAtItemEndNone;
|
||||
_player.muted = true;
|
||||
|
||||
[_photoEditor setPlayerItem:_playerItem];
|
||||
[_photoEditor setPlayerItem:_playerItem forCropRect:_photoEditor.cropRect cropRotation:0.0 cropOrientation:_photoEditor.cropOrientation cropMirrored:_photoEditor.cropMirrored];
|
||||
|
||||
TGDispatchOnMainThread(^
|
||||
{
|
||||
@ -680,14 +680,17 @@
|
||||
[photoEditor setImage:image forCropRect:photoEditor.cropRect cropRotation:photoEditor.cropRotation cropOrientation:photoEditor.cropOrientation cropMirrored:photoEditor.cropMirrored fullSize:true];
|
||||
[photoEditor createResultImageWithCompletion:^(UIImage *result)
|
||||
{
|
||||
if (hasPainting)
|
||||
{
|
||||
result = TGPaintCombineCroppedImages(result, editorValues.paintingData.image, true, photoEditor.originalSize, photoEditor.cropRect, photoEditor.cropOrientation, photoEditor.cropRotation, photoEditor.cropMirrored);
|
||||
[TGPaintingData facilitatePaintingData:editorValues.paintingData];
|
||||
}
|
||||
|
||||
[subscriber putNext:result];
|
||||
[subscriber putCompletion];
|
||||
[_queue dispatch:^{
|
||||
UIImage *final = result;
|
||||
if (hasPainting)
|
||||
{
|
||||
final = TGPaintCombineCroppedImages(final, editorValues.paintingData.image, true, photoEditor.originalSize, photoEditor.cropRect, photoEditor.cropOrientation, photoEditor.cropRotation, photoEditor.cropMirrored);
|
||||
[TGPaintingData facilitatePaintingData:editorValues.paintingData];
|
||||
}
|
||||
|
||||
[subscriber putNext:final];
|
||||
[subscriber putCompletion];
|
||||
}];
|
||||
}];
|
||||
|
||||
return nil;
|
||||
|
@ -217,7 +217,11 @@ UIImage *TGPhotoEditorCrop(UIImage *inputImage, UIImage *paintingImage, UIImageO
|
||||
return TGPhotoEditorVideoCrop(inputImage, paintingImage, orientation, rotation, rect, mirrored, maxSize, originalSize, shouldResize, false);
|
||||
}
|
||||
|
||||
UIImage *TGPhotoEditorVideoCrop(UIImage *inputImage, UIImage *paintingImage, UIImageOrientation orientation, CGFloat rotation, CGRect rect, bool mirrored, CGSize maxSize, CGSize originalSize, bool shouldResize, bool useImageSize)
|
||||
UIImage *TGPhotoEditorVideoCrop(UIImage *inputImage, UIImage *paintingImage, UIImageOrientation orientation, CGFloat rotation, CGRect rect, bool mirrored, CGSize maxSize, CGSize originalSize, bool shouldResize, bool useImageSize) {
|
||||
return TGPhotoEditorVideoExtCrop(inputImage, paintingImage, orientation, rotation, rect, mirrored, maxSize, originalSize, shouldResize, useImageSize, false);
|
||||
}
|
||||
|
||||
UIImage *TGPhotoEditorVideoExtCrop(UIImage *inputImage, UIImage *paintingImage, UIImageOrientation orientation, CGFloat rotation, CGRect rect, bool mirrored, CGSize maxSize, CGSize originalSize, bool shouldResize, bool useImageSize, bool skipImageTransform)
|
||||
{
|
||||
if (iosMajorVersion() < 7)
|
||||
return TGPhotoEditorLegacyCrop(inputImage, paintingImage, orientation, rotation, rect, mirrored, maxSize, shouldResize);
|
||||
@ -244,16 +248,7 @@ UIImage *TGPhotoEditorVideoCrop(UIImage *inputImage, UIImage *paintingImage, UII
|
||||
CGContextSetFillColorWithColor(context, [UIColor blackColor].CGColor);
|
||||
CGContextFillRect(context, CGRectMake(0, 0, outputImageSize.width, outputImageSize.height));
|
||||
CGContextSetInterpolationQuality(context, kCGInterpolationHigh);
|
||||
|
||||
CGSize scales = CGSizeMake(fittedImageSize.width / rect.size.width, fittedImageSize.height / rect.size.height);
|
||||
CGSize rotatedContentSize = TGRotatedContentSize(inputImage.size, rotation);
|
||||
CGAffineTransform transform = CGAffineTransformIdentity;
|
||||
transform = CGAffineTransformTranslate(transform, outputImageSize.width / 2, outputImageSize.height / 2);
|
||||
transform = CGAffineTransformRotate(transform, TGRotationForOrientation(orientation));
|
||||
transform = CGAffineTransformTranslate(transform, (rotatedContentSize.width / 2 - CGRectGetMidX(rect)) * scales.width, (rotatedContentSize.height / 2 - CGRectGetMidY(rect)) * scales.height);
|
||||
transform = CGAffineTransformRotate(transform, rotation);
|
||||
CGContextConcatCTM(context, transform);
|
||||
|
||||
|
||||
UIImage *image = nil;
|
||||
if (shouldResize)
|
||||
{
|
||||
@ -268,10 +263,25 @@ UIImage *TGPhotoEditorVideoCrop(UIImage *inputImage, UIImage *paintingImage, UII
|
||||
image = inputImage;
|
||||
}
|
||||
|
||||
if (skipImageTransform) {
|
||||
[image drawInRect:CGRectMake(0.0, 0.0, outputImageSize.width, outputImageSize.height)];
|
||||
}
|
||||
|
||||
CGSize scales = CGSizeMake(fittedImageSize.width / rect.size.width, fittedImageSize.height / rect.size.height);
|
||||
CGSize rotatedContentSize = TGRotatedContentSize(inputImage.size, rotation);
|
||||
CGAffineTransform transform = CGAffineTransformIdentity;
|
||||
transform = CGAffineTransformTranslate(transform, outputImageSize.width / 2, outputImageSize.height / 2);
|
||||
transform = CGAffineTransformRotate(transform, TGRotationForOrientation(orientation));
|
||||
transform = CGAffineTransformTranslate(transform, (rotatedContentSize.width / 2 - CGRectGetMidX(rect)) * scales.width, (rotatedContentSize.height / 2 - CGRectGetMidY(rect)) * scales.height);
|
||||
transform = CGAffineTransformRotate(transform, rotation);
|
||||
CGContextConcatCTM(context, transform);
|
||||
|
||||
if (mirrored)
|
||||
CGContextScaleCTM(context, -1.0f, 1.0f);
|
||||
|
||||
[image drawAtPoint:CGPointMake(-image.size.width / 2, -image.size.height / 2)];
|
||||
if (!skipImageTransform) {
|
||||
[image drawAtPoint:CGPointMake(-image.size.width / 2, -image.size.height / 2)];
|
||||
}
|
||||
|
||||
if (paintingImage != nil)
|
||||
{
|
||||
|
@ -37,8 +37,6 @@
|
||||
#import "TGPhotoPaintActionsView.h"
|
||||
#import "TGPhotoPaintSettingsView.h"
|
||||
|
||||
#import "TGPhotoStickersView.h"
|
||||
|
||||
#import "TGPhotoPaintSettingsWrapperView.h"
|
||||
#import "TGPhotoBrushSettingsView.h"
|
||||
#import "TGPhotoTextSettingsView.h"
|
||||
@ -94,7 +92,7 @@ const CGFloat TGPhotoPaintStickerKeyboardSize = 260.0f;
|
||||
|
||||
TGPhotoPaintSettingsWrapperView *_settingsViewWrapper;
|
||||
UIView<TGPhotoPaintPanelView> *_settingsView;
|
||||
TGPhotoStickersView *_stickersView;
|
||||
id<TGPhotoPaintStickersScreen> _stickersScreen;
|
||||
|
||||
bool _appeared;
|
||||
|
||||
@ -1005,84 +1003,28 @@ const CGFloat TGPhotoPaintStickerKeyboardSize = 260.0f;
|
||||
|
||||
- (void)presentStickersView
|
||||
{
|
||||
if (_stickersScreen != nil) {
|
||||
[_stickersScreen restore];
|
||||
return;
|
||||
}
|
||||
|
||||
__weak TGPhotoPaintController *weakSelf = self;
|
||||
_stickersContext.presentStickersController(^(id document, bool animated, UIView *view, CGRect rect) {
|
||||
_stickersScreen = _stickersContext.presentStickersController(^(id document, bool animated, UIView *view, CGRect rect) {
|
||||
__strong TGPhotoPaintController *strongSelf = weakSelf;
|
||||
if (strongSelf != nil) {
|
||||
// UIView *snapshot = [view snapshotViewAfterScreenUpdates:false];
|
||||
[strongSelf createNewStickerWithDocument:document animated:animated transitionPoint:CGPointZero stickersView:nil snapshotView:nil];
|
||||
[strongSelf createNewStickerWithDocument:document animated:animated transitionPoint:CGPointZero snapshotView:nil];
|
||||
}
|
||||
});
|
||||
|
||||
// if (_stickersView == nil)
|
||||
// {
|
||||
// TGPhotoStickersView *view = [[TGPhotoStickersView alloc] initWithContext:_context frame:self.view.bounds];
|
||||
// view.parentViewController = self;
|
||||
//
|
||||
// __weak TGPhotoPaintController *weakSelf = self;
|
||||
// __weak TGPhotoStickersView *weakStickersView = view;
|
||||
// view.stickerSelected = ^(TGDocumentMediaAttachment *document, CGPoint transitionPoint, TGPhotoStickersView *stickersView, UIView *snapshotView)
|
||||
// {
|
||||
// __strong TGPhotoPaintController *strongSelf = weakSelf;
|
||||
// if (strongSelf != nil)
|
||||
// [strongSelf createNewStickerWithDocument:document transitionPoint:transitionPoint stickersView:stickersView snapshotView:snapshotView];
|
||||
// };
|
||||
// view.dismissed = ^
|
||||
// {
|
||||
// __strong TGPhotoStickersView *strongStickersView = weakStickersView;
|
||||
// if (strongStickersView != nil)
|
||||
// [strongStickersView removeFromSuperview];
|
||||
// };
|
||||
//
|
||||
// _stickersView = view;
|
||||
// }
|
||||
//
|
||||
// if ([_context currentSizeClass] == UIUserInterfaceSizeClassCompact)
|
||||
// {
|
||||
// _stickersView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
|
||||
// _stickersView.frame = self.view.bounds;
|
||||
// _stickersView.safeAreaInset = self.controllerSafeAreaInset;
|
||||
// [self.parentViewController.view addSubview:_stickersView];
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// _settingsView = _stickersView;
|
||||
// [_stickersView sizeToFit];
|
||||
//
|
||||
// UIView *wrapper = [self settingsViewWrapper];
|
||||
// wrapper.userInteractionEnabled = true;
|
||||
// [wrapper addSubview:_stickersView];
|
||||
//
|
||||
// [self viewWillLayoutSubviews];
|
||||
// }
|
||||
//
|
||||
// _stickersView.outerView = self.parentViewController.view;
|
||||
// _stickersView.targetView = _contentWrapperView;
|
||||
//
|
||||
// [_stickersView present];
|
||||
}
|
||||
|
||||
- (void)createNewStickerWithDocument:(id)document animated:(bool)animated transitionPoint:(CGPoint)transitionPoint stickersView:(TGPhotoStickersView *)stickersView snapshotView:(UIView *)snapshotView
|
||||
- (void)createNewStickerWithDocument:(id)document animated:(bool)animated transitionPoint:(CGPoint)transitionPoint snapshotView:(UIView *)snapshotView
|
||||
{
|
||||
TGPhotoPaintStickerEntity *entity = [[TGPhotoPaintStickerEntity alloc] initWithDocument:document baseSize:[self _stickerBaseSizeForCurrentPainting] animated:animated];
|
||||
[self _setStickerEntityPosition:entity];
|
||||
|
||||
TGPhotoStickerEntityView *stickerView = (TGPhotoStickerEntityView *)[_entitiesContainerView createEntityViewWithEntity:entity];
|
||||
[self _commonEntityViewSetup:stickerView];
|
||||
// stickerView.hidden = true;
|
||||
|
||||
CGFloat rotation = entity.angle - [self startRotation];
|
||||
|
||||
CGRect bounds = stickerView.realBounds;
|
||||
CGPoint center = [stickerView.superview convertPoint:stickerView.center toView:self.parentViewController.view];
|
||||
CGFloat scale = [[stickerView.superview.superview.layer valueForKeyPath:@"transform.scale.x"] floatValue];
|
||||
CGRect targetFrame = CGRectMake(center.x - bounds.size.width * scale / 2.0f, center.y - bounds.size.height * scale / 2.0f, bounds.size.width * scale, bounds.size.height * scale);
|
||||
|
||||
[stickersView dismissWithSnapshotView:snapshotView startPoint:transitionPoint targetFrame:targetFrame targetRotation:rotation completion:^
|
||||
{
|
||||
stickerView.hidden = false;
|
||||
[_entitySelectionView fadeIn];
|
||||
}];
|
||||
|
||||
[self selectEntityView:stickerView];
|
||||
_entitySelectionView.alpha = 0.0f;
|
||||
@ -1802,6 +1744,8 @@ const CGFloat TGPhotoPaintStickerKeyboardSize = 260.0f;
|
||||
{
|
||||
_dismissing = true;
|
||||
|
||||
[_stickersScreen invalidate];
|
||||
|
||||
[_entitySelectionView removeFromSuperview];
|
||||
_entitySelectionView = nil;
|
||||
|
||||
@ -2061,9 +2005,7 @@ const CGFloat TGPhotoPaintStickerKeyboardSize = 260.0f;
|
||||
|
||||
if (_settingsView != nil)
|
||||
[_settingsView setInterfaceOrientation:orientation];
|
||||
|
||||
_stickersView.safeAreaInset = safeAreaInset;
|
||||
|
||||
|
||||
switch (orientation)
|
||||
{
|
||||
case UIInterfaceOrientationLandscapeLeft:
|
||||
@ -2126,14 +2068,7 @@ const CGFloat TGPhotoPaintStickerKeyboardSize = 260.0f;
|
||||
|
||||
if ([_context currentSizeClass] == UIUserInterfaceSizeClassRegular)
|
||||
{
|
||||
if ([_settingsView isKindOfClass:[TGPhotoStickersView class]])
|
||||
{
|
||||
_settingsView.frame = CGRectMake(_settingsViewWrapper.frame.size.width / 6 * 2 - 5 - _settingsView.frame.size.width / 2.0f, _settingsViewWrapper.frame.size.height - _settingsView.frame.size.height - TGPhotoEditorToolbarSize + 10.0f, _settingsView.frame.size.width, _settingsView.frame.size.height);
|
||||
}
|
||||
else
|
||||
{
|
||||
_settingsView.frame = CGRectMake(_settingsViewWrapper.frame.size.width / 2.0f - 10.0f, _settingsViewWrapper.frame.size.height - _settingsView.frame.size.height - TGPhotoEditorToolbarSize - 50.0f, _settingsView.frame.size.width, _settingsView.frame.size.height);
|
||||
}
|
||||
_settingsView.frame = CGRectMake(_settingsViewWrapper.frame.size.width / 2.0f - 10.0f, _settingsViewWrapper.frame.size.height - _settingsView.frame.size.height - TGPhotoEditorToolbarSize - 50.0f, _settingsView.frame.size.width, _settingsView.frame.size.height);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -17,6 +17,7 @@ const NSTimeInterval TGVideoEditMaximumGifDuration = 30.5;
|
||||
@synthesize originalSize = _originalSize;
|
||||
@synthesize cropRect = _cropRect;
|
||||
@synthesize cropOrientation = _cropOrientation;
|
||||
@synthesize cropRotation = _cropRotation;
|
||||
@synthesize cropLockedAspectRatio = _cropLockedAspectRatio;
|
||||
@synthesize cropMirrored = _cropMirrored;
|
||||
@synthesize paintingData = _paintingData;
|
||||
@ -26,6 +27,7 @@ const NSTimeInterval TGVideoEditMaximumGifDuration = 30.5;
|
||||
+ (instancetype)editAdjustmentsWithOriginalSize:(CGSize)originalSize
|
||||
cropRect:(CGRect)cropRect
|
||||
cropOrientation:(UIImageOrientation)cropOrientation
|
||||
cropRotation:(CGFloat)cropRotation
|
||||
cropLockedAspectRatio:(CGFloat)cropLockedAspectRatio
|
||||
cropMirrored:(bool)cropMirrored
|
||||
trimStartValue:(NSTimeInterval)trimStartValue
|
||||
@ -39,6 +41,7 @@ const NSTimeInterval TGVideoEditMaximumGifDuration = 30.5;
|
||||
adjustments->_originalSize = originalSize;
|
||||
adjustments->_cropRect = cropRect;
|
||||
adjustments->_cropOrientation = cropOrientation;
|
||||
adjustments->_cropRotation = cropRotation;
|
||||
adjustments->_cropLockedAspectRatio = cropLockedAspectRatio;
|
||||
adjustments->_cropMirrored = cropMirrored;
|
||||
adjustments->_trimStartValue = trimStartValue;
|
||||
@ -140,13 +143,12 @@ const NSTimeInterval TGVideoEditMaximumGifDuration = 30.5;
|
||||
}
|
||||
adjustments->_cropRect = cropRect;
|
||||
adjustments->_cropOrientation = values.cropOrientation;
|
||||
adjustments->_cropRotation = values.cropRotation;
|
||||
adjustments->_cropLockedAspectRatio = values.cropLockedAspectRatio;
|
||||
adjustments->_cropMirrored = values.cropMirrored;
|
||||
adjustments->_toolValues = values.toolValues;
|
||||
adjustments->_paintingData = values.paintingData;
|
||||
adjustments->_paintingData = [values.paintingData dataForAnimation];
|
||||
adjustments->_sendAsGif = true;
|
||||
adjustments->_preset = TGMediaVideoConversionPresetAnimation;
|
||||
adjustments->_toolValues = values.toolValues;
|
||||
|
||||
return adjustments;
|
||||
}
|
||||
@ -157,11 +159,11 @@ const NSTimeInterval TGVideoEditMaximumGifDuration = 30.5;
|
||||
adjustments->_originalSize = _originalSize;
|
||||
adjustments->_cropRect = _cropRect;
|
||||
adjustments->_cropOrientation = _cropOrientation;
|
||||
adjustments->_cropRotation = _cropRotation;
|
||||
adjustments->_cropLockedAspectRatio = _cropLockedAspectRatio;
|
||||
adjustments->_cropMirrored = _cropMirrored;
|
||||
adjustments->_trimStartValue = _trimStartValue;
|
||||
adjustments->_trimEndValue = _trimEndValue;
|
||||
adjustments->_toolValues = _toolValues;
|
||||
adjustments->_paintingData = _paintingData;
|
||||
adjustments->_sendAsGif = _sendAsGif;
|
||||
adjustments->_preset = preset;
|
||||
@ -187,6 +189,7 @@ const NSTimeInterval TGVideoEditMaximumGifDuration = 30.5;
|
||||
{
|
||||
NSMutableDictionary *dict = [[NSMutableDictionary alloc] init];
|
||||
dict[@"cropOrientation"] = @(self.cropOrientation);
|
||||
dict[@"cropRotation"] = @(self.cropRotation);
|
||||
if ([self cropAppliedForAvatar:false])
|
||||
dict[@"cropRect"] = [NSValue valueWithCGRect:self.cropRect];
|
||||
dict[@"cropMirrored"] = @(self.cropMirrored);
|
||||
@ -279,6 +282,9 @@ const NSTimeInterval TGVideoEditMaximumGifDuration = 30.5;
|
||||
if (self.cropLockedAspectRatio > FLT_EPSILON)
|
||||
return true;
|
||||
|
||||
if (ABS(self.cropRotation) > FLT_EPSILON)
|
||||
return true;
|
||||
|
||||
if (self.cropOrientation != UIImageOrientationUp)
|
||||
return true;
|
||||
|
||||
@ -334,6 +340,9 @@ const NSTimeInterval TGVideoEditMaximumGifDuration = 30.5;
|
||||
if (!_CGRectEqualToRectWithEpsilon(self.cropRect, adjustments.cropRect, [self _cropRectEpsilon]))
|
||||
return false;
|
||||
|
||||
if (ABS(self.cropRotation - adjustments.cropRotation) > FLT_EPSILON)
|
||||
return false;
|
||||
|
||||
if (self.cropOrientation != adjustments.cropOrientation)
|
||||
return false;
|
||||
|
||||
|
@ -980,7 +980,7 @@ typedef enum
|
||||
|
||||
if (trimStartValue > DBL_EPSILON || trimEndValue < _duration - DBL_EPSILON)
|
||||
{
|
||||
adjustments = [TGVideoEditAdjustments editAdjustmentsWithOriginalSize:dimensions cropRect:CGRectMake(0.0f, 0.0f, dimensions.width, dimensions.height) cropOrientation:UIImageOrientationUp cropLockedAspectRatio:1.0 cropMirrored:false trimStartValue:trimStartValue trimEndValue:trimEndValue toolValues:nil paintingData:nil sendAsGif:false preset:TGMediaVideoConversionPresetVideoMessage];
|
||||
adjustments = [TGVideoEditAdjustments editAdjustmentsWithOriginalSize:dimensions cropRect:CGRectMake(0.0f, 0.0f, dimensions.width, dimensions.height) cropOrientation:UIImageOrientationUp cropRotation:0.0 cropLockedAspectRatio:1.0 cropMirrored:false trimStartValue:trimStartValue trimEndValue:trimEndValue toolValues:nil paintingData:nil sendAsGif:false preset:TGMediaVideoConversionPresetVideoMessage];
|
||||
|
||||
duration = trimEndValue - trimStartValue;
|
||||
}
|
||||
|
@ -59,7 +59,7 @@ public enum LegacyAttachmentMenuMediaEditing {
|
||||
case file
|
||||
}
|
||||
|
||||
public func legacyAttachmentMenu(context: AccountContext, peer: Peer, editMediaOptions: LegacyAttachmentMenuMediaEditing?, saveEditedPhotos: Bool, allowGrouping: Bool, hasSchedule: Bool, canSendPolls: Bool, presentationData: PresentationData, parentController: LegacyController, recentlyUsedInlineBots: [Peer], initialCaption: String, openGallery: @escaping () -> Void, openCamera: @escaping (TGAttachmentCameraView?, TGMenuSheetController?) -> Void, openFileGallery: @escaping () -> Void, openWebSearch: @escaping () -> Void, openMap: @escaping () -> Void, openContacts: @escaping () -> Void, openPoll: @escaping () -> Void, presentSelectionLimitExceeded: @escaping () -> Void, presentCantSendMultipleFiles: @escaping () -> Void, presentSchedulePicker: @escaping (@escaping (Int32) -> Void) -> Void, presentTimerPicker: @escaping (@escaping (Int32) -> Void) -> Void, sendMessagesWithSignals: @escaping ([Any]?, Bool, Int32) -> Void, selectRecentlyUsedInlineBot: @escaping (Peer) -> Void, presentStickers: @escaping (@escaping (TelegramMediaFile, Bool, UIView, CGRect) -> Void) -> Void, present: @escaping (ViewController, Any?) -> Void) -> TGMenuSheetController {
|
||||
public func legacyAttachmentMenu(context: AccountContext, peer: Peer, editMediaOptions: LegacyAttachmentMenuMediaEditing?, saveEditedPhotos: Bool, allowGrouping: Bool, hasSchedule: Bool, canSendPolls: Bool, presentationData: PresentationData, parentController: LegacyController, recentlyUsedInlineBots: [Peer], initialCaption: String, openGallery: @escaping () -> Void, openCamera: @escaping (TGAttachmentCameraView?, TGMenuSheetController?) -> Void, openFileGallery: @escaping () -> Void, openWebSearch: @escaping () -> Void, openMap: @escaping () -> Void, openContacts: @escaping () -> Void, openPoll: @escaping () -> Void, presentSelectionLimitExceeded: @escaping () -> Void, presentCantSendMultipleFiles: @escaping () -> Void, presentSchedulePicker: @escaping (@escaping (Int32) -> Void) -> Void, presentTimerPicker: @escaping (@escaping (Int32) -> Void) -> Void, sendMessagesWithSignals: @escaping ([Any]?, Bool, Int32) -> Void, selectRecentlyUsedInlineBot: @escaping (Peer) -> Void, presentStickers: @escaping (@escaping (TelegramMediaFile, Bool, UIView, CGRect) -> Void) -> TGPhotoPaintStickersScreen?, present: @escaping (ViewController, Any?) -> Void) -> TGMenuSheetController {
|
||||
let defaultVideoPreset = defaultVideoPresetForContext(context)
|
||||
UserDefaults.standard.set(defaultVideoPreset.rawValue as NSNumber, forKey: "TG_preferredVideoPreset_v0")
|
||||
|
||||
@ -108,7 +108,7 @@ public func legacyAttachmentMenu(context: AccountContext, peer: Peer, editMediaO
|
||||
|
||||
let paintStickersContext = LegacyPaintStickersContext(context: context)
|
||||
paintStickersContext.presentStickersController = { completion in
|
||||
presentStickers({ file, animated, view, rect in
|
||||
return presentStickers({ file, animated, view, rect in
|
||||
let coder = PostboxEncoder()
|
||||
coder.encodeRootObject(file)
|
||||
completion?(coder.makeData(), animated, view, rect)
|
||||
|
@ -19,12 +19,12 @@ public func guessMimeTypeByFileExtension(_ ext: String) -> String {
|
||||
return TGMimeTypeMap.mimeType(forExtension: ext) ?? "application/binary"
|
||||
}
|
||||
|
||||
public func configureLegacyAssetPicker(_ controller: TGMediaAssetsController, context: AccountContext, peer: Peer, captionsEnabled: Bool = true, storeCreatedAssets: Bool = true, showFileTooltip: Bool = false, initialCaption: String, hasSchedule: Bool, presentWebSearch: (() -> Void)?, presentSelectionLimitExceeded: @escaping () -> Void, presentSchedulePicker: @escaping (@escaping (Int32) -> Void) -> Void, presentTimerPicker: @escaping (@escaping (Int32) -> Void) -> Void, presentStickers: @escaping (@escaping (TelegramMediaFile, Bool, UIView, CGRect) -> Void) -> Void) {
|
||||
public func configureLegacyAssetPicker(_ controller: TGMediaAssetsController, context: AccountContext, peer: Peer, captionsEnabled: Bool = true, storeCreatedAssets: Bool = true, showFileTooltip: Bool = false, initialCaption: String, hasSchedule: Bool, presentWebSearch: (() -> Void)?, presentSelectionLimitExceeded: @escaping () -> Void, presentSchedulePicker: @escaping (@escaping (Int32) -> Void) -> Void, presentTimerPicker: @escaping (@escaping (Int32) -> Void) -> Void, presentStickers: @escaping (@escaping (TelegramMediaFile, Bool, UIView, CGRect) -> Void) -> TGPhotoPaintStickersScreen?) {
|
||||
let isSecretChat = peer.id.namespace == Namespaces.Peer.SecretChat
|
||||
|
||||
let paintStickersContext = LegacyPaintStickersContext(context: context)
|
||||
paintStickersContext.presentStickersController = { completion in
|
||||
presentStickers({ file, animated, view, rect in
|
||||
return presentStickers({ file, animated, view, rect in
|
||||
let coder = PostboxEncoder()
|
||||
coder.encodeRootObject(file)
|
||||
completion?(coder.makeData(), animated, view, rect)
|
||||
|
@ -45,6 +45,7 @@ private class LegacyPaintStickerEntity: LegacyPaintEntity {
|
||||
let file: TelegramMediaFile
|
||||
let entity: TGPhotoPaintStickerEntity
|
||||
let animated: Bool
|
||||
let durationPromise = Promise<Double>()
|
||||
|
||||
var source: AnimatedStickerNodeSource?
|
||||
var frameSource: AnimatedStickerFrameSource?
|
||||
@ -81,6 +82,8 @@ private class LegacyPaintStickerEntity: LegacyPaintEntity {
|
||||
|
||||
strongSelf.frameQueue = frameQueue
|
||||
strongSelf.frameSource = frameSource
|
||||
|
||||
strongSelf.durationPromise.set(.single(Double(frameSource.frameCount) / Double(frameSource.frameRate)))
|
||||
}
|
||||
}
|
||||
}))
|
||||
@ -106,6 +109,10 @@ private class LegacyPaintStickerEntity: LegacyPaintEntity {
|
||||
self.disposable.dispose()
|
||||
}
|
||||
|
||||
var duration: Signal<Double, NoError> {
|
||||
return self.durationPromise.get()
|
||||
}
|
||||
|
||||
private func render(width: Int, height: Int, bytesPerRow: Int, data: Data, type: AnimationRendererFrameType) -> CIImage? {
|
||||
let calculatedBytesPerRow = (4 * Int(width) + 15) & (~15)
|
||||
assert(bytesPerRow == calculatedBytesPerRow)
|
||||
@ -160,6 +167,7 @@ private class LegacyPaintStickerEntity: LegacyPaintEntity {
|
||||
completion(image)
|
||||
} else {
|
||||
let _ = (self.imagePromise.get()
|
||||
|> take(1)
|
||||
|> deliverOn(self.queue)).start(next: { [weak self] image in
|
||||
if let strongSelf = self {
|
||||
strongSelf.cachedCIImage = CIImage(image: image)
|
||||
@ -246,6 +254,33 @@ public final class LegacyPaintEntityRenderer: NSObject, TGPhotoPaintEntityRender
|
||||
|
||||
}
|
||||
|
||||
public func duration() -> Signal<Double, NoError> {
|
||||
var durations: [Signal<Double, NoError>] = []
|
||||
for entity in self.entities {
|
||||
if let sticker = entity as? LegacyPaintStickerEntity, sticker.animated {
|
||||
durations.append(sticker.duration)
|
||||
}
|
||||
}
|
||||
|
||||
func gcd(_ a: Int32, _ b: Int32) -> Int32 {
|
||||
let remainder = a % b
|
||||
if remainder != 0 {
|
||||
return gcd(b, remainder)
|
||||
} else {
|
||||
return b
|
||||
}
|
||||
}
|
||||
|
||||
func lcm(_ x: Int32, _ y: Int32) -> Int32 {
|
||||
return x / gcd(x, y) * y
|
||||
}
|
||||
|
||||
return combineLatest(durations)
|
||||
|> map { durations in
|
||||
return min(6.0, Double(durations.reduce(1) { lcm(Int32($0), Int32($1)) }))
|
||||
}
|
||||
}
|
||||
|
||||
public func entities(for time: CMTime, size: CGSize, completion: (([CIImage]?) -> Void)!) {
|
||||
let entities = self.entities
|
||||
let maxSide = max(size.width, size.height)
|
||||
@ -307,7 +342,7 @@ public final class LegacyPaintEntityRenderer: NSObject, TGPhotoPaintEntityRender
|
||||
}
|
||||
|
||||
public final class LegacyPaintStickersContext: NSObject, TGPhotoPaintStickersContext {
|
||||
public var presentStickersController: ((((Any?, Bool, UIView?, CGRect) -> Void)?) -> Void)!
|
||||
public var presentStickersController: ((((Any?, Bool, UIView?, CGRect) -> Void)?) -> TGPhotoPaintStickersScreen?)!
|
||||
|
||||
private let context: AccountContext
|
||||
|
||||
|
@ -106,7 +106,7 @@ private func preparedShareItem(account: Account, to peerId: PeerId, value: [Stri
|
||||
cropRect = CGRect(x: (size.width - shortestSide) / 2.0, y: (size.height - shortestSide) / 2.0, width: shortestSide, height: shortestSide)
|
||||
}
|
||||
|
||||
adjustments = TGVideoEditAdjustments(originalSize: size, cropRect: cropRect, cropOrientation: .up, cropLockedAspectRatio: 1.0, cropMirrored: false, trimStartValue: 0.0, trimEndValue: 0.0, toolValues: nil, paintingData: nil, sendAsGif: false, preset: TGMediaVideoConversionPresetVideoMessage)
|
||||
adjustments = TGVideoEditAdjustments(originalSize: size, cropRect: cropRect, cropOrientation: .up, cropRotation: 0.0, cropLockedAspectRatio: 1.0, cropMirrored: false, trimStartValue: 0.0, trimEndValue: 0.0, toolValues: nil, paintingData: nil, sendAsGif: false, preset: TGMediaVideoConversionPresetVideoMessage)
|
||||
}
|
||||
}
|
||||
var finalDuration: Double = CMTimeGetSeconds(asset.duration)
|
||||
|
@ -6060,6 +6060,9 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
return true
|
||||
})
|
||||
strongSelf.present(controller, in: .window(.root))
|
||||
return controller
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
})
|
||||
}
|
||||
@ -6132,6 +6135,9 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
return true
|
||||
})
|
||||
strongSelf.present(controller, in: .window(.root))
|
||||
return controller
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}, present: { [weak self] c, a in
|
||||
self?.present(c, in: .window(.root), with: a)
|
||||
@ -6313,9 +6319,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
}, presentTimerPicker: { [weak self] done in
|
||||
if let strongSelf = self {
|
||||
strongSelf.presentTimerPicker(style: .media, completion: { [weak self] time in
|
||||
if let strongSelf = self {
|
||||
done(time)
|
||||
}
|
||||
done(time)
|
||||
})
|
||||
}
|
||||
}, presentStickers: { [weak self] completion in
|
||||
@ -6325,6 +6329,9 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
return true
|
||||
})
|
||||
strongSelf.present(controller, in: .window(.root))
|
||||
return controller
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
})
|
||||
controller.descriptionGenerator = legacyAssetPickerItemGenerator()
|
||||
|
@ -368,6 +368,7 @@ final class ChatMediaInputNodeInteraction {
|
||||
var highlightedGifMode: ChatMediaInputGifMode = .recent
|
||||
var previewedStickerPackItem: StickerPreviewPeekItem?
|
||||
var appearanceTransition: CGFloat = 1.0
|
||||
var displayStickerPlaceholder = true
|
||||
|
||||
init(navigateToCollectionId: @escaping (ItemCollectionId) -> Void, navigateBackToStickers: @escaping () -> Void, setGifMode: @escaping (ChatMediaInputGifMode) -> Void, openSettings: @escaping () -> Void, toggleSearch: @escaping (Bool, ChatMediaInputSearchMode?, String) -> Void, openPeerSpecificSettings: @escaping () -> Void, dismissPeerSpecificSettings: @escaping () -> Void, clearRecentlyUsedStickers: @escaping () -> Void) {
|
||||
self.navigateToCollectionId = navigateToCollectionId
|
||||
|
@ -254,9 +254,12 @@ final class ChatMediaInputStickerGridItemNode: GridItemNode {
|
||||
let boundingSize = CGSize(width: sideSize, height: sideSize)
|
||||
|
||||
self.item = item
|
||||
|
||||
|
||||
|
||||
if self.currentState == nil || self.currentState!.0 !== item.account || self.currentState!.1 != item.stickerItem {
|
||||
if !item.inputNodeInteraction.displayStickerPlaceholder {
|
||||
self.removePlaceholder(animated: false)
|
||||
}
|
||||
|
||||
if let dimensions = item.stickerItem.file.dimensions {
|
||||
if item.stickerItem.file.isAnimatedSticker {
|
||||
if self.animationNode == nil {
|
||||
|
@ -16,6 +16,7 @@ import PresentationDataUtils
|
||||
import SearchBarNode
|
||||
import UndoUI
|
||||
import SegmentedControlNode
|
||||
import LegacyComponents
|
||||
|
||||
private final class DrawingStickersScreenNode: ViewControllerTracingNode {
|
||||
private let context: AccountContext
|
||||
@ -274,7 +275,7 @@ private final class DrawingStickersScreenNode: ViewControllerTracingNode {
|
||||
}
|
||||
})
|
||||
self.inputNodeInteraction.stickerSettings = ChatInterfaceStickerSettings(loopAnimatedStickers: true)
|
||||
|
||||
self.inputNodeInteraction.displayStickerPlaceholder = false
|
||||
|
||||
self.addSubnode(self.topPanel)
|
||||
|
||||
@ -288,8 +289,8 @@ private final class DrawingStickersScreenNode: ViewControllerTracingNode {
|
||||
self.addSubnode(self.topSeparatorNode)
|
||||
self.addSubnode(self.bottomSeparatorNode)
|
||||
|
||||
let trendingInteraction = TrendingPaneInteraction(installPack: { [weak self] info in
|
||||
}, openPack: { [weak self] info in
|
||||
let trendingInteraction = TrendingPaneInteraction(installPack: { info in
|
||||
}, openPack: { info in
|
||||
}, getItemIsPreviewed: { item in
|
||||
return false
|
||||
}, openSearch: {
|
||||
@ -481,7 +482,7 @@ private final class DrawingStickersScreenNode: ViewControllerTracingNode {
|
||||
}
|
||||
|
||||
@objc private func cancelPressed() {
|
||||
self.dismiss?()
|
||||
self.animateOut()
|
||||
}
|
||||
|
||||
private func setHighlightedItemCollectionId(_ collectionId: ItemCollectionId) {
|
||||
@ -819,11 +820,16 @@ private final class DrawingStickersScreenNode: ViewControllerTracingNode {
|
||||
}
|
||||
|
||||
func animateIn() {
|
||||
self.isUserInteractionEnabled = true
|
||||
self.isHidden = false
|
||||
self.layer.animatePosition(from: CGPoint(x: self.layer.position.x, y: self.layer.position.y + self.layer.bounds.size.height), to: self.layer.position, duration: 0.5, timingFunction: kCAMediaTimingFunctionSpring)
|
||||
}
|
||||
|
||||
func animateOut() {
|
||||
self.layer.animatePosition(from: self.layer.position, to: CGPoint(x: self.layer.position.x, y: self.layer.position.y + self.layer.bounds.size.height), duration: 0.3, timingFunction: kCAMediaTimingFunctionSpring)
|
||||
self.isUserInteractionEnabled = false
|
||||
self.layer.animatePosition(from: self.layer.position, to: CGPoint(x: self.layer.position.x, y: self.layer.position.y + self.layer.bounds.size.height), duration: 0.3, timingFunction: kCAMediaTimingFunctionSpring, removeOnCompletion: false, completion: { [weak self] _ in
|
||||
self?.isHidden = true
|
||||
})
|
||||
}
|
||||
|
||||
func containerLayoutUpdated(_ layout: ContainerViewLayout, navigationHeight: CGFloat, transition: ContainedViewLayoutTransition) {
|
||||
@ -836,7 +842,7 @@ private final class DrawingStickersScreenNode: ViewControllerTracingNode {
|
||||
}
|
||||
}
|
||||
|
||||
final class DrawingStickersScreen: ViewController {
|
||||
final class DrawingStickersScreen: ViewController, TGPhotoPaintStickersScreen {
|
||||
private let context: AccountContext
|
||||
var selectSticker: ((FileMediaReference, ASDisplayNode, CGRect) -> Bool)?
|
||||
|
||||
@ -896,6 +902,7 @@ final class DrawingStickersScreen: ViewController {
|
||||
context: self.context,
|
||||
selectSticker: { [weak self] file, sourceNode, sourceRect in
|
||||
if let strongSelf = self, let selectSticker = strongSelf.selectSticker {
|
||||
(strongSelf.displayNode as! DrawingStickersScreenNode).animateOut()
|
||||
return selectSticker(file, sourceNode, sourceRect)
|
||||
} else {
|
||||
return false
|
||||
@ -928,4 +935,12 @@ final class DrawingStickersScreen: ViewController {
|
||||
|
||||
self.controllerNode.containerLayoutUpdated(layout, navigationHeight: 0.0, transition: transition)
|
||||
}
|
||||
|
||||
func restore() {
|
||||
(self.displayNode as! DrawingStickersScreenNode).animateIn()
|
||||
}
|
||||
|
||||
func invalidate() {
|
||||
self.dismiss()
|
||||
}
|
||||
}
|
||||
|
@ -287,7 +287,13 @@ public func fetchVideoLibraryMediaResource(account: Account, resource: VideoLibr
|
||||
}
|
||||
}
|
||||
let updatedSize = Atomic<Int>(value: 0)
|
||||
let entityRenderer = adjustments.flatMap { LegacyPaintEntityRenderer(account: account, adjustments: $0) }
|
||||
let entityRenderer: LegacyPaintEntityRenderer? = adjustments.flatMap { adjustments in
|
||||
if let paintingData = adjustments.paintingData, paintingData.hasAnimation {
|
||||
return LegacyPaintEntityRenderer(account: account, adjustments: adjustments)
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
let signal = TGMediaVideoConverter.convert(avAsset, adjustments: adjustments, watcher: VideoConversionWatcher(update: { path, size in
|
||||
var value = stat()
|
||||
if stat(path, &value) == 0 {
|
||||
@ -379,24 +385,47 @@ func fetchLocalFileVideoMediaResource(account: Account, resource: LocalFileVideo
|
||||
}
|
||||
}
|
||||
let updatedSize = Atomic<Int>(value: 0)
|
||||
let entityRenderer = adjustments.flatMap { LegacyPaintEntityRenderer(account: account, adjustments: $0) }
|
||||
let entityRenderer: LegacyPaintEntityRenderer? = adjustments.flatMap { adjustments in
|
||||
if let paintingData = adjustments.paintingData, paintingData.hasAnimation {
|
||||
return LegacyPaintEntityRenderer(account: account, adjustments: adjustments)
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
let signal: SSignal
|
||||
if filteredPath.contains(".jpg") {
|
||||
if filteredPath.contains(".jpg"), let entityRenderer = entityRenderer {
|
||||
if let data = try? Data(contentsOf: URL(fileURLWithPath: filteredPath), options: [.mappedRead]), let image = UIImage(data: data) {
|
||||
signal = TGMediaVideoConverter.renderUIImage(image, adjustments: adjustments, watcher: VideoConversionWatcher(update: { path, size in
|
||||
var value = stat()
|
||||
if stat(path, &value) == 0 {
|
||||
if let data = try? Data(contentsOf: URL(fileURLWithPath: path), options: [.mappedRead]) {
|
||||
var range: Range<Int>?
|
||||
let _ = updatedSize.modify { updatedSize in
|
||||
range = updatedSize ..< Int(value.st_size)
|
||||
return Int(value.st_size)
|
||||
let durationSignal: SSignal = SSignal(generator: { subscriber in
|
||||
let disposable = (entityRenderer.duration()).start(next: { duration in
|
||||
subscriber?.putNext(duration)
|
||||
subscriber?.putCompletion()
|
||||
})
|
||||
|
||||
return SBlockDisposable(block: {
|
||||
disposable.dispose()
|
||||
})
|
||||
})
|
||||
|
||||
signal = durationSignal.map(toSignal: { duration -> SSignal? in
|
||||
if let duration = duration as? Double {
|
||||
return TGMediaVideoConverter.renderUIImage(image, duration: duration, adjustments: adjustments, watcher: VideoConversionWatcher(update: { path, size in
|
||||
var value = stat()
|
||||
if stat(path, &value) == 0 {
|
||||
if let data = try? Data(contentsOf: URL(fileURLWithPath: path), options: [.mappedRead]) {
|
||||
var range: Range<Int>?
|
||||
let _ = updatedSize.modify { updatedSize in
|
||||
range = updatedSize ..< Int(value.st_size)
|
||||
return Int(value.st_size)
|
||||
}
|
||||
//print("size = \(Int(value.st_size)), range: \(range!)")
|
||||
subscriber.putNext(.dataPart(resourceOffset: range!.lowerBound, data: data, range: range!, complete: false))
|
||||
}
|
||||
}
|
||||
//print("size = \(Int(value.st_size)), range: \(range!)")
|
||||
subscriber.putNext(.dataPart(resourceOffset: range!.lowerBound, data: data, range: range!, complete: false))
|
||||
}
|
||||
}), entityRenderer: entityRenderer)!
|
||||
} else {
|
||||
return SSignal.single(nil)
|
||||
}
|
||||
}), entityRenderer: entityRenderer)!
|
||||
})
|
||||
} else {
|
||||
signal = SSignal.single(nil)
|
||||
}
|
||||
|
@ -11,7 +11,7 @@ import ShareController
|
||||
import LegacyUI
|
||||
import LegacyMediaPickerUI
|
||||
|
||||
func presentedLegacyCamera(context: AccountContext, peer: Peer, cameraView: TGAttachmentCameraView?, menuController: TGMenuSheetController?, parentController: ViewController, editingMedia: Bool, saveCapturedPhotos: Bool, mediaGrouping: Bool, initialCaption: String, hasSchedule: Bool, sendMessagesWithSignals: @escaping ([Any]?, Bool, Int32) -> Void, recognizedQRCode: @escaping (String) -> Void = { _ in }, presentSchedulePicker: @escaping (@escaping (Int32) -> Void) -> Void, presentTimerPicker: @escaping (@escaping (Int32) -> Void) -> Void, presentStickers: @escaping (@escaping (TelegramMediaFile, Bool, UIView, CGRect) -> Void) -> Void) {
|
||||
func presentedLegacyCamera(context: AccountContext, peer: Peer, cameraView: TGAttachmentCameraView?, menuController: TGMenuSheetController?, parentController: ViewController, editingMedia: Bool, saveCapturedPhotos: Bool, mediaGrouping: Bool, initialCaption: String, hasSchedule: Bool, sendMessagesWithSignals: @escaping ([Any]?, Bool, Int32) -> Void, recognizedQRCode: @escaping (String) -> Void = { _ in }, presentSchedulePicker: @escaping (@escaping (Int32) -> Void) -> Void, presentTimerPicker: @escaping (@escaping (Int32) -> Void) -> Void, presentStickers: @escaping (@escaping (TelegramMediaFile, Bool, UIView, CGRect) -> Void) -> TGPhotoPaintStickersScreen?) {
|
||||
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||
let legacyController = LegacyController(presentation: .custom, theme: presentationData.theme)
|
||||
legacyController.supportedOrientations = ViewControllerSupportedOrientations(regularSize: .portrait, compactSize: .portrait)
|
||||
@ -65,7 +65,7 @@ func presentedLegacyCamera(context: AccountContext, peer: Peer, cameraView: TGAt
|
||||
|
||||
let paintStickersContext = LegacyPaintStickersContext(context: context)
|
||||
paintStickersContext.presentStickersController = { completion in
|
||||
presentStickers({ file, animated, view, rect in
|
||||
return presentStickers({ file, animated, view, rect in
|
||||
let coder = PostboxEncoder()
|
||||
coder.encodeRootObject(file)
|
||||
completion?(coder.makeData(), animated, view, rect)
|
||||
|
Loading…
x
Reference in New Issue
Block a user