mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-12-19 12:49:02 +00:00
Video editor fixes
This commit is contained in:
parent
9c9fd6cc03
commit
ef5756702c
@ -4,8 +4,6 @@
|
|||||||
|
|
||||||
@interface PGPhotoEditorValues : NSObject <TGMediaEditAdjustments>
|
@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;
|
+ (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
|
@end
|
||||||
|
|||||||
@ -25,6 +25,7 @@
|
|||||||
@property (nonatomic, readonly) CGSize originalSize;
|
@property (nonatomic, readonly) CGSize originalSize;
|
||||||
@property (nonatomic, readonly) CGRect cropRect;
|
@property (nonatomic, readonly) CGRect cropRect;
|
||||||
@property (nonatomic, readonly) UIImageOrientation cropOrientation;
|
@property (nonatomic, readonly) UIImageOrientation cropOrientation;
|
||||||
|
@property (nonatomic, readonly) CGFloat cropRotation;
|
||||||
@property (nonatomic, readonly) CGFloat cropLockedAspectRatio;
|
@property (nonatomic, readonly) CGFloat cropLockedAspectRatio;
|
||||||
@property (nonatomic, readonly) bool cropMirrored;
|
@property (nonatomic, readonly) bool cropMirrored;
|
||||||
@property (nonatomic, readonly) bool sendAsGif;
|
@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 *)convertAVAsset:(AVAsset *)avAsset adjustments:(TGMediaVideoEditAdjustments *)adjustments watcher:(TGMediaVideoFileWatcher *)watcher inhibitAudio:(bool)inhibitAudio entityRenderer:(id<TGPhotoPaintEntityRenderer>)entityRenderer;
|
||||||
+ (SSignal *)hashForAVAsset:(AVAsset *)avAsset adjustments:(TGMediaVideoEditAdjustments *)adjustments;
|
+ (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;
|
+ (NSUInteger)estimatedSizeForPreset:(TGMediaVideoConversionPreset)preset duration:(NSTimeInterval)duration hasAudio:(bool)hasAudio;
|
||||||
+ (TGMediaVideoConversionPreset)bestAvailablePresetForDimensions:(CGSize)dimensions;
|
+ (TGMediaVideoConversionPreset)bestAvailablePresetForDimensions:(CGSize)dimensions;
|
||||||
|
|||||||
@ -26,6 +26,8 @@
|
|||||||
|
|
||||||
+ (instancetype)dataWithPaintingImagePath:(NSString *)imagePath;
|
+ (instancetype)dataWithPaintingImagePath:(NSString *)imagePath;
|
||||||
|
|
||||||
|
- (instancetype)dataForAnimation;
|
||||||
|
|
||||||
+ (void)storePaintingData:(TGPaintingData *)data inContext:(TGMediaEditingContext *)context forItem:(id<TGMediaEditableItem>)item forVideo:(bool)video;
|
+ (void)storePaintingData:(TGPaintingData *)data inContext:(TGMediaEditingContext *)context forItem:(id<TGMediaEditableItem>)item forVideo:(bool)video;
|
||||||
+ (void)facilitatePaintingData:(TGPaintingData *)data;
|
+ (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 *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 *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);
|
UIImage *TGPhotoEditorFitImage(UIImage *image, CGSize maxSize);
|
||||||
CGSize TGRotatedContentSize(CGSize contentSize, CGFloat rotation);
|
CGSize TGRotatedContentSize(CGSize contentSize, CGFloat rotation);
|
||||||
|
|
||||||
|
|||||||
@ -18,6 +18,13 @@
|
|||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
@protocol TGPhotoPaintStickersScreen <NSObject>
|
||||||
|
|
||||||
|
- (void)restore;
|
||||||
|
- (void)invalidate;
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
@protocol TGPhotoPaintStickersContext <NSObject>
|
@protocol TGPhotoPaintStickersContext <NSObject>
|
||||||
|
|
||||||
- (int64_t)documentIdForDocument:(id)document;
|
- (int64_t)documentIdForDocument:(id)document;
|
||||||
@ -25,6 +32,6 @@
|
|||||||
|
|
||||||
- (UIView<TGPhotoPaintStickerRenderView> *)stickerViewForDocument:(id)document;
|
- (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
|
@end
|
||||||
|
|||||||
@ -37,6 +37,7 @@ typedef enum
|
|||||||
+ (instancetype)editAdjustmentsWithOriginalSize:(CGSize)originalSize
|
+ (instancetype)editAdjustmentsWithOriginalSize:(CGSize)originalSize
|
||||||
cropRect:(CGRect)cropRect
|
cropRect:(CGRect)cropRect
|
||||||
cropOrientation:(UIImageOrientation)cropOrientation
|
cropOrientation:(UIImageOrientation)cropOrientation
|
||||||
|
cropRotation:(CGFloat)cropRotation
|
||||||
cropLockedAspectRatio:(CGFloat)cropLockedAspectRatio
|
cropLockedAspectRatio:(CGFloat)cropLockedAspectRatio
|
||||||
cropMirrored:(bool)cropMirrored
|
cropMirrored:(bool)cropMirrored
|
||||||
trimStartValue:(NSTimeInterval)trimStartValue
|
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
|
NSString *const kGPUImagePassthroughFragmentShaderString = SHADER_STRING
|
||||||
(
|
(
|
||||||
varying highp vec2 texCoord;
|
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
|
@implementation GPUImageFilter
|
||||||
|
|
||||||
|
|||||||
@ -40,7 +40,7 @@
|
|||||||
- (void)cleanup;
|
- (void)cleanup;
|
||||||
|
|
||||||
- (void)setImage:(UIImage *)image forCropRect:(CGRect)cropRect cropRotation:(CGFloat)cropRotation cropOrientation:(UIImageOrientation)cropOrientation cropMirrored:(bool)cropMirrored fullSize:(bool)fullSize;
|
- (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)setCIImage:(CIImage *)ciImage;
|
||||||
|
|
||||||
- (void)processAnimated:(bool)animated completion:(void (^)(void))completion;
|
- (void)processAnimated:(bool)animated completion:(void (^)(void))completion;
|
||||||
|
|||||||
@ -11,6 +11,7 @@
|
|||||||
#import "PGPhotoEditorPicture.h"
|
#import "PGPhotoEditorPicture.h"
|
||||||
|
|
||||||
#import "GPUImageTextureInput.h"
|
#import "GPUImageTextureInput.h"
|
||||||
|
#import "GPUImageCropFilter.h"
|
||||||
|
|
||||||
#import <LegacyComponents/PGPhotoEditorValues.h>
|
#import <LegacyComponents/PGPhotoEditorValues.h>
|
||||||
#import <LegacyComponents/TGVideoEditAdjustments.h>
|
#import <LegacyComponents/TGVideoEditAdjustments.h>
|
||||||
@ -43,6 +44,9 @@
|
|||||||
id<TGMediaEditAdjustments> _initialAdjustments;
|
id<TGMediaEditAdjustments> _initialAdjustments;
|
||||||
|
|
||||||
GPUImageOutput *_currentInput;
|
GPUImageOutput *_currentInput;
|
||||||
|
GPUImageCropFilter *_cropFilter;
|
||||||
|
GPUImageRotationMode _rotationMode;
|
||||||
|
|
||||||
NSArray *_currentProcessChain;
|
NSArray *_currentProcessChain;
|
||||||
GPUImageOutput <GPUImageInput> *_finalFilter;
|
GPUImageOutput <GPUImageInput> *_finalFilter;
|
||||||
|
|
||||||
@ -159,7 +163,7 @@
|
|||||||
_fullSize = fullSize;
|
_fullSize = fullSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setPlayerItem:(AVPlayerItem *)playerItem {
|
- (void)setPlayerItem:(AVPlayerItem *)playerItem forCropRect:(CGRect)cropRect cropRotation:(CGFloat)cropRotation cropOrientation:(UIImageOrientation)cropOrientation cropMirrored:(bool)cropMirrored {
|
||||||
[_toolComposer invalidate];
|
[_toolComposer invalidate];
|
||||||
_currentProcessChain = nil;
|
_currentProcessChain = nil;
|
||||||
|
|
||||||
@ -167,6 +171,36 @@
|
|||||||
PGVideoMovie *movie = [[PGVideoMovie alloc] initWithPlayerItem:playerItem];
|
PGVideoMovie *movie = [[PGVideoMovie alloc] initWithPlayerItem:playerItem];
|
||||||
_currentInput = movie;
|
_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;
|
_fullSize = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -341,7 +375,12 @@
|
|||||||
_currentProcessChain = processChain;
|
_currentProcessChain = processChain;
|
||||||
|
|
||||||
GPUImageOutput <GPUImageInput> *lastFilter = ((PGPhotoProcessPass *)_currentProcessChain.firstObject).filter;
|
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;
|
NSInteger chainLength = _currentProcessChain.count;
|
||||||
if (chainLength > 1)
|
if (chainLength > 1)
|
||||||
@ -460,7 +499,7 @@
|
|||||||
{
|
{
|
||||||
TGVideoEditAdjustments *initialAdjustments = (TGVideoEditAdjustments *)_initialAdjustments;
|
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 originalSize = _originalSize;
|
||||||
@synthesize cropRect = _cropRect;
|
@synthesize cropRect = _cropRect;
|
||||||
@synthesize cropOrientation = _cropOrientation;
|
@synthesize cropOrientation = _cropOrientation;
|
||||||
|
@synthesize cropRotation = _cropRotation;
|
||||||
@synthesize cropLockedAspectRatio = _cropLockedAspectRatio;
|
@synthesize cropLockedAspectRatio = _cropLockedAspectRatio;
|
||||||
@synthesize cropMirrored = _cropMirrored;
|
@synthesize cropMirrored = _cropMirrored;
|
||||||
@synthesize paintingData = _paintingData;
|
@synthesize paintingData = _paintingData;
|
||||||
|
|||||||
@ -851,18 +851,13 @@
|
|||||||
[data writeToFile:filePath atomically:true];
|
[data writeToFile:filePath atomically:true];
|
||||||
dict[@"url"] = [NSURL fileURLWithPath:filePath];
|
dict[@"url"] = [NSURL fileURLWithPath:filePath];
|
||||||
|
|
||||||
|
|
||||||
if ([adjustments cropAppliedForAvatar:false] || adjustments.hasPainting || adjustments.toolsApplied)
|
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;
|
UIImage *paintingImage = adjustments.paintingData.stillImage;
|
||||||
if (paintingImage == nil) {
|
if (paintingImage == nil) {
|
||||||
paintingImage = adjustments.paintingData.image;
|
paintingImage = adjustments.paintingData.image;
|
||||||
}
|
}
|
||||||
if (adjustments.toolsApplied) {
|
UIImage *thumbnailImage = TGPhotoEditorVideoExtCrop(image, paintingImage, adjustments.cropOrientation, adjustments.cropRotation, adjustments.cropRect, adjustments.cropMirrored, TGScaleToFill(asset.dimensions, CGSizeMake(384, 384)), adjustments.originalSize, true, true, true);
|
||||||
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);
|
|
||||||
if (thumbnailImage != nil) {
|
if (thumbnailImage != nil) {
|
||||||
dict[@"previewImage"] = thumbnailImage;
|
dict[@"previewImage"] = thumbnailImage;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -647,7 +647,9 @@
|
|||||||
[_paintingImageCache setImage:image forKey:itemId attributes:NULL];
|
[_paintingImageCache setImage:image forKey:itemId attributes:NULL];
|
||||||
|
|
||||||
NSData *imageData = UIImagePNGRepresentation(image);
|
NSData *imageData = UIImagePNGRepresentation(image);
|
||||||
|
[[NSFileManager defaultManager] removeItemAtURL:imageUrl error:nil];
|
||||||
bool imageSuccess = [imageData writeToURL:imageUrl options:NSDataWritingAtomic 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];
|
bool dataSuccess = [data writeToURL:dataUrl options:NSDataWritingAtomic error:nil];
|
||||||
|
|
||||||
if (imageSuccess && imageOutUrl != NULL)
|
if (imageSuccess && imageOutUrl != NULL)
|
||||||
@ -664,6 +666,7 @@
|
|||||||
[_stillPaintingImageCache setImage:stillImage forKey:itemId attributes:NULL];
|
[_stillPaintingImageCache setImage:stillImage forKey:itemId attributes:NULL];
|
||||||
|
|
||||||
NSData *stillImageData = UIImagePNGRepresentation(stillImage);
|
NSData *stillImageData = UIImagePNGRepresentation(stillImage);
|
||||||
|
[[NSFileManager defaultManager] removeItemAtURL:stillImageUrl error:nil];
|
||||||
[stillImageData writeToURL:stillImageUrl options:NSDataWritingAtomic error:nil];
|
[stillImageData writeToURL:stillImageUrl options:NSDataWritingAtomic error:nil];
|
||||||
|
|
||||||
if (video)
|
if (video)
|
||||||
|
|||||||
@ -1108,7 +1108,7 @@
|
|||||||
|
|
||||||
strongSelf->_photoEditor = [[PGPhotoEditor alloc] initWithOriginalSize:strongSelf->_videoDimensions adjustments:adjustments forVideo:true enableStickers:true];
|
strongSelf->_photoEditor = [[PGPhotoEditor alloc] initWithOriginalSize:strongSelf->_videoDimensions adjustments:adjustments forVideo:true enableStickers:true];
|
||||||
strongSelf->_photoEditor.previewOutput = strongSelf->_videoView;
|
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->_photoEditor processAnimated:false completion:nil];
|
||||||
|
|
||||||
[strongSelf _seekToPosition:adjustments.trimStartValue manual:false];
|
[strongSelf _seekToPosition:adjustments.trimStartValue manual:false];
|
||||||
@ -1383,7 +1383,7 @@
|
|||||||
[self updatePlayerRange:trimEndValue];
|
[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];
|
[self.item.editingContext setAdjustments:updatedAdjustments forItem:self.item.editableMediaItem];
|
||||||
|
|
||||||
if (sendAsGif)
|
if (sendAsGif)
|
||||||
@ -1475,7 +1475,7 @@
|
|||||||
UIImageOrientation cropOrientation = (adjustments != nil) ? adjustments.cropOrientation : UIImageOrientationUp;
|
UIImageOrientation cropOrientation = (adjustments != nil) ? adjustments.cropOrientation : UIImageOrientationUp;
|
||||||
CGFloat cropLockedAspectRatio = (adjustments != nil) ? adjustments.cropLockedAspectRatio : 0.0f;
|
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];
|
[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];
|
[subscriber putError:error];
|
||||||
return;
|
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];
|
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];
|
[subscriber putError:error];
|
||||||
return;
|
return;
|
||||||
@ -351,17 +351,6 @@
|
|||||||
if (adjustments.paintingData.imagePath != nil)
|
if (adjustments.paintingData.imagePath != nil)
|
||||||
overlayImage = [UIImage imageWithContentsOfFile:adjustments.paintingData.imagePath];
|
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;
|
AVMutableVideoComposition *videoComposition;
|
||||||
if (entityRenderer != nil || adjustments.toolsApplied) {
|
if (entityRenderer != nil || adjustments.toolsApplied) {
|
||||||
PGPhotoEditor *editor = nil;
|
PGPhotoEditor *editor = nil;
|
||||||
@ -504,7 +493,7 @@
|
|||||||
return output;
|
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) {
|
if (image == nil) {
|
||||||
TGMediaSampleBufferProcessor *videoProcessor = nil;
|
TGMediaSampleBufferProcessor *videoProcessor = nil;
|
||||||
@ -579,7 +568,7 @@
|
|||||||
|
|
||||||
CGSize dimensions = CGSizeZero;
|
CGSize dimensions = CGSizeZero;
|
||||||
NSDictionary *outputSettings = nil;
|
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];
|
AVMutableComposition *composition = [AVMutableComposition composition];
|
||||||
|
|
||||||
AVAssetTrack *videoTrack = [[avAsset tracksWithMediaType:AVMediaTypeVideo] firstObject];
|
AVAssetTrack *videoTrack = [[avAsset tracksWithMediaType:AVMediaTypeVideo] firstObject];
|
||||||
|
|||||||
@ -46,6 +46,13 @@
|
|||||||
return paintingData;
|
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
|
+ (void)storePaintingData:(TGPaintingData *)data inContext:(TGMediaEditingContext *)context forItem:(id<TGMediaEditableItem>)item forVideo:(bool)video
|
||||||
{
|
{
|
||||||
[[TGPaintingData queue] dispatch:^
|
[[TGPaintingData queue] dispatch:^
|
||||||
|
|||||||
@ -406,7 +406,7 @@
|
|||||||
_player.actionAtItemEnd = AVPlayerActionAtItemEndNone;
|
_player.actionAtItemEnd = AVPlayerActionAtItemEndNone;
|
||||||
_player.muted = true;
|
_player.muted = true;
|
||||||
|
|
||||||
[_photoEditor setPlayerItem:_playerItem];
|
[_photoEditor setPlayerItem:_playerItem forCropRect:_photoEditor.cropRect cropRotation:0.0 cropOrientation:_photoEditor.cropOrientation cropMirrored:_photoEditor.cropMirrored];
|
||||||
|
|
||||||
TGDispatchOnMainThread(^
|
TGDispatchOnMainThread(^
|
||||||
{
|
{
|
||||||
@ -680,14 +680,17 @@
|
|||||||
[photoEditor setImage:image forCropRect:photoEditor.cropRect cropRotation:photoEditor.cropRotation cropOrientation:photoEditor.cropOrientation cropMirrored:photoEditor.cropMirrored fullSize:true];
|
[photoEditor setImage:image forCropRect:photoEditor.cropRect cropRotation:photoEditor.cropRotation cropOrientation:photoEditor.cropOrientation cropMirrored:photoEditor.cropMirrored fullSize:true];
|
||||||
[photoEditor createResultImageWithCompletion:^(UIImage *result)
|
[photoEditor createResultImageWithCompletion:^(UIImage *result)
|
||||||
{
|
{
|
||||||
if (hasPainting)
|
[_queue dispatch:^{
|
||||||
{
|
UIImage *final = result;
|
||||||
result = TGPaintCombineCroppedImages(result, editorValues.paintingData.image, true, photoEditor.originalSize, photoEditor.cropRect, photoEditor.cropOrientation, photoEditor.cropRotation, photoEditor.cropMirrored);
|
if (hasPainting)
|
||||||
[TGPaintingData facilitatePaintingData:editorValues.paintingData];
|
{
|
||||||
}
|
final = TGPaintCombineCroppedImages(final, editorValues.paintingData.image, true, photoEditor.originalSize, photoEditor.cropRect, photoEditor.cropOrientation, photoEditor.cropRotation, photoEditor.cropMirrored);
|
||||||
|
[TGPaintingData facilitatePaintingData:editorValues.paintingData];
|
||||||
|
}
|
||||||
|
|
||||||
[subscriber putNext:result];
|
[subscriber putNext:final];
|
||||||
[subscriber putCompletion];
|
[subscriber putCompletion];
|
||||||
|
}];
|
||||||
}];
|
}];
|
||||||
|
|
||||||
return nil;
|
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);
|
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)
|
if (iosMajorVersion() < 7)
|
||||||
return TGPhotoEditorLegacyCrop(inputImage, paintingImage, orientation, rotation, rect, mirrored, maxSize, shouldResize);
|
return TGPhotoEditorLegacyCrop(inputImage, paintingImage, orientation, rotation, rect, mirrored, maxSize, shouldResize);
|
||||||
@ -245,15 +249,6 @@ UIImage *TGPhotoEditorVideoCrop(UIImage *inputImage, UIImage *paintingImage, UII
|
|||||||
CGContextFillRect(context, CGRectMake(0, 0, outputImageSize.width, outputImageSize.height));
|
CGContextFillRect(context, CGRectMake(0, 0, outputImageSize.width, outputImageSize.height));
|
||||||
CGContextSetInterpolationQuality(context, kCGInterpolationHigh);
|
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;
|
UIImage *image = nil;
|
||||||
if (shouldResize)
|
if (shouldResize)
|
||||||
{
|
{
|
||||||
@ -268,10 +263,25 @@ UIImage *TGPhotoEditorVideoCrop(UIImage *inputImage, UIImage *paintingImage, UII
|
|||||||
image = inputImage;
|
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)
|
if (mirrored)
|
||||||
CGContextScaleCTM(context, -1.0f, 1.0f);
|
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)
|
if (paintingImage != nil)
|
||||||
{
|
{
|
||||||
|
|||||||
@ -37,8 +37,6 @@
|
|||||||
#import "TGPhotoPaintActionsView.h"
|
#import "TGPhotoPaintActionsView.h"
|
||||||
#import "TGPhotoPaintSettingsView.h"
|
#import "TGPhotoPaintSettingsView.h"
|
||||||
|
|
||||||
#import "TGPhotoStickersView.h"
|
|
||||||
|
|
||||||
#import "TGPhotoPaintSettingsWrapperView.h"
|
#import "TGPhotoPaintSettingsWrapperView.h"
|
||||||
#import "TGPhotoBrushSettingsView.h"
|
#import "TGPhotoBrushSettingsView.h"
|
||||||
#import "TGPhotoTextSettingsView.h"
|
#import "TGPhotoTextSettingsView.h"
|
||||||
@ -94,7 +92,7 @@ const CGFloat TGPhotoPaintStickerKeyboardSize = 260.0f;
|
|||||||
|
|
||||||
TGPhotoPaintSettingsWrapperView *_settingsViewWrapper;
|
TGPhotoPaintSettingsWrapperView *_settingsViewWrapper;
|
||||||
UIView<TGPhotoPaintPanelView> *_settingsView;
|
UIView<TGPhotoPaintPanelView> *_settingsView;
|
||||||
TGPhotoStickersView *_stickersView;
|
id<TGPhotoPaintStickersScreen> _stickersScreen;
|
||||||
|
|
||||||
bool _appeared;
|
bool _appeared;
|
||||||
|
|
||||||
@ -1005,84 +1003,28 @@ const CGFloat TGPhotoPaintStickerKeyboardSize = 260.0f;
|
|||||||
|
|
||||||
- (void)presentStickersView
|
- (void)presentStickersView
|
||||||
{
|
{
|
||||||
|
if (_stickersScreen != nil) {
|
||||||
|
[_stickersScreen restore];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
__weak TGPhotoPaintController *weakSelf = self;
|
__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;
|
__strong TGPhotoPaintController *strongSelf = weakSelf;
|
||||||
if (strongSelf != nil) {
|
if (strongSelf != nil) {
|
||||||
// UIView *snapshot = [view snapshotViewAfterScreenUpdates:false];
|
// 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];
|
TGPhotoPaintStickerEntity *entity = [[TGPhotoPaintStickerEntity alloc] initWithDocument:document baseSize:[self _stickerBaseSizeForCurrentPainting] animated:animated];
|
||||||
[self _setStickerEntityPosition:entity];
|
[self _setStickerEntityPosition:entity];
|
||||||
|
|
||||||
TGPhotoStickerEntityView *stickerView = (TGPhotoStickerEntityView *)[_entitiesContainerView createEntityViewWithEntity:entity];
|
TGPhotoStickerEntityView *stickerView = (TGPhotoStickerEntityView *)[_entitiesContainerView createEntityViewWithEntity:entity];
|
||||||
[self _commonEntityViewSetup:stickerView];
|
[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];
|
[self selectEntityView:stickerView];
|
||||||
_entitySelectionView.alpha = 0.0f;
|
_entitySelectionView.alpha = 0.0f;
|
||||||
@ -1802,6 +1744,8 @@ const CGFloat TGPhotoPaintStickerKeyboardSize = 260.0f;
|
|||||||
{
|
{
|
||||||
_dismissing = true;
|
_dismissing = true;
|
||||||
|
|
||||||
|
[_stickersScreen invalidate];
|
||||||
|
|
||||||
[_entitySelectionView removeFromSuperview];
|
[_entitySelectionView removeFromSuperview];
|
||||||
_entitySelectionView = nil;
|
_entitySelectionView = nil;
|
||||||
|
|
||||||
@ -2062,8 +2006,6 @@ const CGFloat TGPhotoPaintStickerKeyboardSize = 260.0f;
|
|||||||
if (_settingsView != nil)
|
if (_settingsView != nil)
|
||||||
[_settingsView setInterfaceOrientation:orientation];
|
[_settingsView setInterfaceOrientation:orientation];
|
||||||
|
|
||||||
_stickersView.safeAreaInset = safeAreaInset;
|
|
||||||
|
|
||||||
switch (orientation)
|
switch (orientation)
|
||||||
{
|
{
|
||||||
case UIInterfaceOrientationLandscapeLeft:
|
case UIInterfaceOrientationLandscapeLeft:
|
||||||
@ -2126,14 +2068,7 @@ const CGFloat TGPhotoPaintStickerKeyboardSize = 260.0f;
|
|||||||
|
|
||||||
if ([_context currentSizeClass] == UIUserInterfaceSizeClassRegular)
|
if ([_context currentSizeClass] == UIUserInterfaceSizeClassRegular)
|
||||||
{
|
{
|
||||||
if ([_settingsView isKindOfClass:[TGPhotoStickersView class]])
|
_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 / 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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|||||||
@ -17,6 +17,7 @@ const NSTimeInterval TGVideoEditMaximumGifDuration = 30.5;
|
|||||||
@synthesize originalSize = _originalSize;
|
@synthesize originalSize = _originalSize;
|
||||||
@synthesize cropRect = _cropRect;
|
@synthesize cropRect = _cropRect;
|
||||||
@synthesize cropOrientation = _cropOrientation;
|
@synthesize cropOrientation = _cropOrientation;
|
||||||
|
@synthesize cropRotation = _cropRotation;
|
||||||
@synthesize cropLockedAspectRatio = _cropLockedAspectRatio;
|
@synthesize cropLockedAspectRatio = _cropLockedAspectRatio;
|
||||||
@synthesize cropMirrored = _cropMirrored;
|
@synthesize cropMirrored = _cropMirrored;
|
||||||
@synthesize paintingData = _paintingData;
|
@synthesize paintingData = _paintingData;
|
||||||
@ -26,6 +27,7 @@ const NSTimeInterval TGVideoEditMaximumGifDuration = 30.5;
|
|||||||
+ (instancetype)editAdjustmentsWithOriginalSize:(CGSize)originalSize
|
+ (instancetype)editAdjustmentsWithOriginalSize:(CGSize)originalSize
|
||||||
cropRect:(CGRect)cropRect
|
cropRect:(CGRect)cropRect
|
||||||
cropOrientation:(UIImageOrientation)cropOrientation
|
cropOrientation:(UIImageOrientation)cropOrientation
|
||||||
|
cropRotation:(CGFloat)cropRotation
|
||||||
cropLockedAspectRatio:(CGFloat)cropLockedAspectRatio
|
cropLockedAspectRatio:(CGFloat)cropLockedAspectRatio
|
||||||
cropMirrored:(bool)cropMirrored
|
cropMirrored:(bool)cropMirrored
|
||||||
trimStartValue:(NSTimeInterval)trimStartValue
|
trimStartValue:(NSTimeInterval)trimStartValue
|
||||||
@ -39,6 +41,7 @@ const NSTimeInterval TGVideoEditMaximumGifDuration = 30.5;
|
|||||||
adjustments->_originalSize = originalSize;
|
adjustments->_originalSize = originalSize;
|
||||||
adjustments->_cropRect = cropRect;
|
adjustments->_cropRect = cropRect;
|
||||||
adjustments->_cropOrientation = cropOrientation;
|
adjustments->_cropOrientation = cropOrientation;
|
||||||
|
adjustments->_cropRotation = cropRotation;
|
||||||
adjustments->_cropLockedAspectRatio = cropLockedAspectRatio;
|
adjustments->_cropLockedAspectRatio = cropLockedAspectRatio;
|
||||||
adjustments->_cropMirrored = cropMirrored;
|
adjustments->_cropMirrored = cropMirrored;
|
||||||
adjustments->_trimStartValue = trimStartValue;
|
adjustments->_trimStartValue = trimStartValue;
|
||||||
@ -140,13 +143,12 @@ const NSTimeInterval TGVideoEditMaximumGifDuration = 30.5;
|
|||||||
}
|
}
|
||||||
adjustments->_cropRect = cropRect;
|
adjustments->_cropRect = cropRect;
|
||||||
adjustments->_cropOrientation = values.cropOrientation;
|
adjustments->_cropOrientation = values.cropOrientation;
|
||||||
|
adjustments->_cropRotation = values.cropRotation;
|
||||||
adjustments->_cropLockedAspectRatio = values.cropLockedAspectRatio;
|
adjustments->_cropLockedAspectRatio = values.cropLockedAspectRatio;
|
||||||
adjustments->_cropMirrored = values.cropMirrored;
|
adjustments->_cropMirrored = values.cropMirrored;
|
||||||
adjustments->_toolValues = values.toolValues;
|
adjustments->_paintingData = [values.paintingData dataForAnimation];
|
||||||
adjustments->_paintingData = values.paintingData;
|
|
||||||
adjustments->_sendAsGif = true;
|
adjustments->_sendAsGif = true;
|
||||||
adjustments->_preset = TGMediaVideoConversionPresetAnimation;
|
adjustments->_preset = TGMediaVideoConversionPresetAnimation;
|
||||||
adjustments->_toolValues = values.toolValues;
|
|
||||||
|
|
||||||
return adjustments;
|
return adjustments;
|
||||||
}
|
}
|
||||||
@ -157,11 +159,11 @@ const NSTimeInterval TGVideoEditMaximumGifDuration = 30.5;
|
|||||||
adjustments->_originalSize = _originalSize;
|
adjustments->_originalSize = _originalSize;
|
||||||
adjustments->_cropRect = _cropRect;
|
adjustments->_cropRect = _cropRect;
|
||||||
adjustments->_cropOrientation = _cropOrientation;
|
adjustments->_cropOrientation = _cropOrientation;
|
||||||
|
adjustments->_cropRotation = _cropRotation;
|
||||||
adjustments->_cropLockedAspectRatio = _cropLockedAspectRatio;
|
adjustments->_cropLockedAspectRatio = _cropLockedAspectRatio;
|
||||||
adjustments->_cropMirrored = _cropMirrored;
|
adjustments->_cropMirrored = _cropMirrored;
|
||||||
adjustments->_trimStartValue = _trimStartValue;
|
adjustments->_trimStartValue = _trimStartValue;
|
||||||
adjustments->_trimEndValue = _trimEndValue;
|
adjustments->_trimEndValue = _trimEndValue;
|
||||||
adjustments->_toolValues = _toolValues;
|
|
||||||
adjustments->_paintingData = _paintingData;
|
adjustments->_paintingData = _paintingData;
|
||||||
adjustments->_sendAsGif = _sendAsGif;
|
adjustments->_sendAsGif = _sendAsGif;
|
||||||
adjustments->_preset = preset;
|
adjustments->_preset = preset;
|
||||||
@ -187,6 +189,7 @@ const NSTimeInterval TGVideoEditMaximumGifDuration = 30.5;
|
|||||||
{
|
{
|
||||||
NSMutableDictionary *dict = [[NSMutableDictionary alloc] init];
|
NSMutableDictionary *dict = [[NSMutableDictionary alloc] init];
|
||||||
dict[@"cropOrientation"] = @(self.cropOrientation);
|
dict[@"cropOrientation"] = @(self.cropOrientation);
|
||||||
|
dict[@"cropRotation"] = @(self.cropRotation);
|
||||||
if ([self cropAppliedForAvatar:false])
|
if ([self cropAppliedForAvatar:false])
|
||||||
dict[@"cropRect"] = [NSValue valueWithCGRect:self.cropRect];
|
dict[@"cropRect"] = [NSValue valueWithCGRect:self.cropRect];
|
||||||
dict[@"cropMirrored"] = @(self.cropMirrored);
|
dict[@"cropMirrored"] = @(self.cropMirrored);
|
||||||
@ -279,6 +282,9 @@ const NSTimeInterval TGVideoEditMaximumGifDuration = 30.5;
|
|||||||
if (self.cropLockedAspectRatio > FLT_EPSILON)
|
if (self.cropLockedAspectRatio > FLT_EPSILON)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
if (ABS(self.cropRotation) > FLT_EPSILON)
|
||||||
|
return true;
|
||||||
|
|
||||||
if (self.cropOrientation != UIImageOrientationUp)
|
if (self.cropOrientation != UIImageOrientationUp)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
@ -334,6 +340,9 @@ const NSTimeInterval TGVideoEditMaximumGifDuration = 30.5;
|
|||||||
if (!_CGRectEqualToRectWithEpsilon(self.cropRect, adjustments.cropRect, [self _cropRectEpsilon]))
|
if (!_CGRectEqualToRectWithEpsilon(self.cropRect, adjustments.cropRect, [self _cropRectEpsilon]))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
if (ABS(self.cropRotation - adjustments.cropRotation) > FLT_EPSILON)
|
||||||
|
return false;
|
||||||
|
|
||||||
if (self.cropOrientation != adjustments.cropOrientation)
|
if (self.cropOrientation != adjustments.cropOrientation)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
|||||||
@ -980,7 +980,7 @@ typedef enum
|
|||||||
|
|
||||||
if (trimStartValue > DBL_EPSILON || trimEndValue < _duration - DBL_EPSILON)
|
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;
|
duration = trimEndValue - trimStartValue;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -59,7 +59,7 @@ public enum LegacyAttachmentMenuMediaEditing {
|
|||||||
case file
|
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)
|
let defaultVideoPreset = defaultVideoPresetForContext(context)
|
||||||
UserDefaults.standard.set(defaultVideoPreset.rawValue as NSNumber, forKey: "TG_preferredVideoPreset_v0")
|
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)
|
let paintStickersContext = LegacyPaintStickersContext(context: context)
|
||||||
paintStickersContext.presentStickersController = { completion in
|
paintStickersContext.presentStickersController = { completion in
|
||||||
presentStickers({ file, animated, view, rect in
|
return presentStickers({ file, animated, view, rect in
|
||||||
let coder = PostboxEncoder()
|
let coder = PostboxEncoder()
|
||||||
coder.encodeRootObject(file)
|
coder.encodeRootObject(file)
|
||||||
completion?(coder.makeData(), animated, view, rect)
|
completion?(coder.makeData(), animated, view, rect)
|
||||||
|
|||||||
@ -19,12 +19,12 @@ public func guessMimeTypeByFileExtension(_ ext: String) -> String {
|
|||||||
return TGMimeTypeMap.mimeType(forExtension: ext) ?? "application/binary"
|
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 isSecretChat = peer.id.namespace == Namespaces.Peer.SecretChat
|
||||||
|
|
||||||
let paintStickersContext = LegacyPaintStickersContext(context: context)
|
let paintStickersContext = LegacyPaintStickersContext(context: context)
|
||||||
paintStickersContext.presentStickersController = { completion in
|
paintStickersContext.presentStickersController = { completion in
|
||||||
presentStickers({ file, animated, view, rect in
|
return presentStickers({ file, animated, view, rect in
|
||||||
let coder = PostboxEncoder()
|
let coder = PostboxEncoder()
|
||||||
coder.encodeRootObject(file)
|
coder.encodeRootObject(file)
|
||||||
completion?(coder.makeData(), animated, view, rect)
|
completion?(coder.makeData(), animated, view, rect)
|
||||||
|
|||||||
@ -45,6 +45,7 @@ private class LegacyPaintStickerEntity: LegacyPaintEntity {
|
|||||||
let file: TelegramMediaFile
|
let file: TelegramMediaFile
|
||||||
let entity: TGPhotoPaintStickerEntity
|
let entity: TGPhotoPaintStickerEntity
|
||||||
let animated: Bool
|
let animated: Bool
|
||||||
|
let durationPromise = Promise<Double>()
|
||||||
|
|
||||||
var source: AnimatedStickerNodeSource?
|
var source: AnimatedStickerNodeSource?
|
||||||
var frameSource: AnimatedStickerFrameSource?
|
var frameSource: AnimatedStickerFrameSource?
|
||||||
@ -81,6 +82,8 @@ private class LegacyPaintStickerEntity: LegacyPaintEntity {
|
|||||||
|
|
||||||
strongSelf.frameQueue = frameQueue
|
strongSelf.frameQueue = frameQueue
|
||||||
strongSelf.frameSource = frameSource
|
strongSelf.frameSource = frameSource
|
||||||
|
|
||||||
|
strongSelf.durationPromise.set(.single(Double(frameSource.frameCount) / Double(frameSource.frameRate)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}))
|
}))
|
||||||
@ -106,6 +109,10 @@ private class LegacyPaintStickerEntity: LegacyPaintEntity {
|
|||||||
self.disposable.dispose()
|
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? {
|
private func render(width: Int, height: Int, bytesPerRow: Int, data: Data, type: AnimationRendererFrameType) -> CIImage? {
|
||||||
let calculatedBytesPerRow = (4 * Int(width) + 15) & (~15)
|
let calculatedBytesPerRow = (4 * Int(width) + 15) & (~15)
|
||||||
assert(bytesPerRow == calculatedBytesPerRow)
|
assert(bytesPerRow == calculatedBytesPerRow)
|
||||||
@ -160,6 +167,7 @@ private class LegacyPaintStickerEntity: LegacyPaintEntity {
|
|||||||
completion(image)
|
completion(image)
|
||||||
} else {
|
} else {
|
||||||
let _ = (self.imagePromise.get()
|
let _ = (self.imagePromise.get()
|
||||||
|
|> take(1)
|
||||||
|> deliverOn(self.queue)).start(next: { [weak self] image in
|
|> deliverOn(self.queue)).start(next: { [weak self] image in
|
||||||
if let strongSelf = self {
|
if let strongSelf = self {
|
||||||
strongSelf.cachedCIImage = CIImage(image: image)
|
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)!) {
|
public func entities(for time: CMTime, size: CGSize, completion: (([CIImage]?) -> Void)!) {
|
||||||
let entities = self.entities
|
let entities = self.entities
|
||||||
let maxSide = max(size.width, size.height)
|
let maxSide = max(size.width, size.height)
|
||||||
@ -307,7 +342,7 @@ public final class LegacyPaintEntityRenderer: NSObject, TGPhotoPaintEntityRender
|
|||||||
}
|
}
|
||||||
|
|
||||||
public final class LegacyPaintStickersContext: NSObject, TGPhotoPaintStickersContext {
|
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
|
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)
|
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)
|
var finalDuration: Double = CMTimeGetSeconds(asset.duration)
|
||||||
|
|||||||
@ -6060,6 +6060,9 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||||||
return true
|
return true
|
||||||
})
|
})
|
||||||
strongSelf.present(controller, in: .window(.root))
|
strongSelf.present(controller, in: .window(.root))
|
||||||
|
return controller
|
||||||
|
} else {
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -6132,6 +6135,9 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||||||
return true
|
return true
|
||||||
})
|
})
|
||||||
strongSelf.present(controller, in: .window(.root))
|
strongSelf.present(controller, in: .window(.root))
|
||||||
|
return controller
|
||||||
|
} else {
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
}, present: { [weak self] c, a in
|
}, present: { [weak self] c, a in
|
||||||
self?.present(c, in: .window(.root), with: a)
|
self?.present(c, in: .window(.root), with: a)
|
||||||
@ -6313,9 +6319,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||||||
}, presentTimerPicker: { [weak self] done in
|
}, presentTimerPicker: { [weak self] done in
|
||||||
if let strongSelf = self {
|
if let strongSelf = self {
|
||||||
strongSelf.presentTimerPicker(style: .media, completion: { [weak self] time in
|
strongSelf.presentTimerPicker(style: .media, completion: { [weak self] time in
|
||||||
if let strongSelf = self {
|
done(time)
|
||||||
done(time)
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}, presentStickers: { [weak self] completion in
|
}, presentStickers: { [weak self] completion in
|
||||||
@ -6325,6 +6329,9 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||||||
return true
|
return true
|
||||||
})
|
})
|
||||||
strongSelf.present(controller, in: .window(.root))
|
strongSelf.present(controller, in: .window(.root))
|
||||||
|
return controller
|
||||||
|
} else {
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
controller.descriptionGenerator = legacyAssetPickerItemGenerator()
|
controller.descriptionGenerator = legacyAssetPickerItemGenerator()
|
||||||
|
|||||||
@ -368,6 +368,7 @@ final class ChatMediaInputNodeInteraction {
|
|||||||
var highlightedGifMode: ChatMediaInputGifMode = .recent
|
var highlightedGifMode: ChatMediaInputGifMode = .recent
|
||||||
var previewedStickerPackItem: StickerPreviewPeekItem?
|
var previewedStickerPackItem: StickerPreviewPeekItem?
|
||||||
var appearanceTransition: CGFloat = 1.0
|
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) {
|
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
|
self.navigateToCollectionId = navigateToCollectionId
|
||||||
|
|||||||
@ -255,8 +255,11 @@ final class ChatMediaInputStickerGridItemNode: GridItemNode {
|
|||||||
|
|
||||||
self.item = item
|
self.item = item
|
||||||
|
|
||||||
|
|
||||||
if self.currentState == nil || self.currentState!.0 !== item.account || self.currentState!.1 != item.stickerItem {
|
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 let dimensions = item.stickerItem.file.dimensions {
|
||||||
if item.stickerItem.file.isAnimatedSticker {
|
if item.stickerItem.file.isAnimatedSticker {
|
||||||
if self.animationNode == nil {
|
if self.animationNode == nil {
|
||||||
|
|||||||
@ -16,6 +16,7 @@ import PresentationDataUtils
|
|||||||
import SearchBarNode
|
import SearchBarNode
|
||||||
import UndoUI
|
import UndoUI
|
||||||
import SegmentedControlNode
|
import SegmentedControlNode
|
||||||
|
import LegacyComponents
|
||||||
|
|
||||||
private final class DrawingStickersScreenNode: ViewControllerTracingNode {
|
private final class DrawingStickersScreenNode: ViewControllerTracingNode {
|
||||||
private let context: AccountContext
|
private let context: AccountContext
|
||||||
@ -274,7 +275,7 @@ private final class DrawingStickersScreenNode: ViewControllerTracingNode {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
self.inputNodeInteraction.stickerSettings = ChatInterfaceStickerSettings(loopAnimatedStickers: true)
|
self.inputNodeInteraction.stickerSettings = ChatInterfaceStickerSettings(loopAnimatedStickers: true)
|
||||||
|
self.inputNodeInteraction.displayStickerPlaceholder = false
|
||||||
|
|
||||||
self.addSubnode(self.topPanel)
|
self.addSubnode(self.topPanel)
|
||||||
|
|
||||||
@ -288,8 +289,8 @@ private final class DrawingStickersScreenNode: ViewControllerTracingNode {
|
|||||||
self.addSubnode(self.topSeparatorNode)
|
self.addSubnode(self.topSeparatorNode)
|
||||||
self.addSubnode(self.bottomSeparatorNode)
|
self.addSubnode(self.bottomSeparatorNode)
|
||||||
|
|
||||||
let trendingInteraction = TrendingPaneInteraction(installPack: { [weak self] info in
|
let trendingInteraction = TrendingPaneInteraction(installPack: { info in
|
||||||
}, openPack: { [weak self] info in
|
}, openPack: { info in
|
||||||
}, getItemIsPreviewed: { item in
|
}, getItemIsPreviewed: { item in
|
||||||
return false
|
return false
|
||||||
}, openSearch: {
|
}, openSearch: {
|
||||||
@ -481,7 +482,7 @@ private final class DrawingStickersScreenNode: ViewControllerTracingNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@objc private func cancelPressed() {
|
@objc private func cancelPressed() {
|
||||||
self.dismiss?()
|
self.animateOut()
|
||||||
}
|
}
|
||||||
|
|
||||||
private func setHighlightedItemCollectionId(_ collectionId: ItemCollectionId) {
|
private func setHighlightedItemCollectionId(_ collectionId: ItemCollectionId) {
|
||||||
@ -819,11 +820,16 @@ private final class DrawingStickersScreenNode: ViewControllerTracingNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func animateIn() {
|
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)
|
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() {
|
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) {
|
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
|
private let context: AccountContext
|
||||||
var selectSticker: ((FileMediaReference, ASDisplayNode, CGRect) -> Bool)?
|
var selectSticker: ((FileMediaReference, ASDisplayNode, CGRect) -> Bool)?
|
||||||
|
|
||||||
@ -896,6 +902,7 @@ final class DrawingStickersScreen: ViewController {
|
|||||||
context: self.context,
|
context: self.context,
|
||||||
selectSticker: { [weak self] file, sourceNode, sourceRect in
|
selectSticker: { [weak self] file, sourceNode, sourceRect in
|
||||||
if let strongSelf = self, let selectSticker = strongSelf.selectSticker {
|
if let strongSelf = self, let selectSticker = strongSelf.selectSticker {
|
||||||
|
(strongSelf.displayNode as! DrawingStickersScreenNode).animateOut()
|
||||||
return selectSticker(file, sourceNode, sourceRect)
|
return selectSticker(file, sourceNode, sourceRect)
|
||||||
} else {
|
} else {
|
||||||
return false
|
return false
|
||||||
@ -928,4 +935,12 @@ final class DrawingStickersScreen: ViewController {
|
|||||||
|
|
||||||
self.controllerNode.containerLayoutUpdated(layout, navigationHeight: 0.0, transition: transition)
|
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 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
|
let signal = TGMediaVideoConverter.convert(avAsset, adjustments: adjustments, watcher: VideoConversionWatcher(update: { path, size in
|
||||||
var value = stat()
|
var value = stat()
|
||||||
if stat(path, &value) == 0 {
|
if stat(path, &value) == 0 {
|
||||||
@ -379,24 +385,47 @@ func fetchLocalFileVideoMediaResource(account: Account, resource: LocalFileVideo
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
let updatedSize = Atomic<Int>(value: 0)
|
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
|
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) {
|
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
|
let durationSignal: SSignal = SSignal(generator: { subscriber in
|
||||||
var value = stat()
|
let disposable = (entityRenderer.duration()).start(next: { duration in
|
||||||
if stat(path, &value) == 0 {
|
subscriber?.putNext(duration)
|
||||||
if let data = try? Data(contentsOf: URL(fileURLWithPath: path), options: [.mappedRead]) {
|
subscriber?.putCompletion()
|
||||||
var range: Range<Int>?
|
})
|
||||||
let _ = updatedSize.modify { updatedSize in
|
|
||||||
range = updatedSize ..< Int(value.st_size)
|
return SBlockDisposable(block: {
|
||||||
return Int(value.st_size)
|
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!)")
|
}), entityRenderer: entityRenderer)!
|
||||||
subscriber.putNext(.dataPart(resourceOffset: range!.lowerBound, data: data, range: range!, complete: false))
|
} else {
|
||||||
}
|
return SSignal.single(nil)
|
||||||
}
|
}
|
||||||
}), entityRenderer: entityRenderer)!
|
})
|
||||||
} else {
|
} else {
|
||||||
signal = SSignal.single(nil)
|
signal = SSignal.single(nil)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -11,7 +11,7 @@ import ShareController
|
|||||||
import LegacyUI
|
import LegacyUI
|
||||||
import LegacyMediaPickerUI
|
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 presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||||
let legacyController = LegacyController(presentation: .custom, theme: presentationData.theme)
|
let legacyController = LegacyController(presentation: .custom, theme: presentationData.theme)
|
||||||
legacyController.supportedOrientations = ViewControllerSupportedOrientations(regularSize: .portrait, compactSize: .portrait)
|
legacyController.supportedOrientations = ViewControllerSupportedOrientations(regularSize: .portrait, compactSize: .portrait)
|
||||||
@ -65,7 +65,7 @@ func presentedLegacyCamera(context: AccountContext, peer: Peer, cameraView: TGAt
|
|||||||
|
|
||||||
let paintStickersContext = LegacyPaintStickersContext(context: context)
|
let paintStickersContext = LegacyPaintStickersContext(context: context)
|
||||||
paintStickersContext.presentStickersController = { completion in
|
paintStickersContext.presentStickersController = { completion in
|
||||||
presentStickers({ file, animated, view, rect in
|
return presentStickers({ file, animated, view, rect in
|
||||||
let coder = PostboxEncoder()
|
let coder = PostboxEncoder()
|
||||||
coder.encodeRootObject(file)
|
coder.encodeRootObject(file)
|
||||||
completion?(coder.makeData(), animated, view, rect)
|
completion?(coder.makeData(), animated, view, rect)
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user