Video Editing

This commit is contained in:
Ilya Laktyushin 2020-05-23 13:26:53 +03:00
parent 29b23c767f
commit 7741978b7e
131 changed files with 3072 additions and 631 deletions

View File

@ -156,6 +156,7 @@ swift_library(
":AppIntentVocabularyResources",
":InfoPlistStringResources",
"//submodules/LegacyComponents:LegacyComponentsResources",
"//submodules/LegacyComponents:LegacyComponentsAssets",
"//submodules/OverlayStatusController:OverlayStatusControllerResources",
"//submodules/PasswordSetupUI:PasswordSetupUIResources",
"//submodules/PasswordSetupUI:PasswordSetupUIAssets",

View File

@ -60,12 +60,12 @@ public enum AnimatedStickerPlaybackMode {
case still(AnimatedStickerPlaybackPosition)
}
private final class AnimatedStickerFrame {
let data: Data
let type: AnimationRendererFrameType
let width: Int
let height: Int
let bytesPerRow: Int
public final class AnimatedStickerFrame {
public let data: Data
public let type: AnimationRendererFrameType
public let width: Int
public let height: Int
public let bytesPerRow: Int
let index: Int
let isLastFrame: Bool
@ -80,7 +80,7 @@ private final class AnimatedStickerFrame {
}
}
private protocol AnimatedStickerFrameSource: class {
public protocol AnimatedStickerFrameSource: class {
var frameRate: Int { get }
var frameCount: Int { get }
@ -97,7 +97,7 @@ private final class AnimatedStickerFrameSourceWrapper {
}
@available(iOS 9.0, *)
private final class AnimatedStickerCachedFrameSource: AnimatedStickerFrameSource {
public final class AnimatedStickerCachedFrameSource: AnimatedStickerFrameSource {
private let queue: Queue
private var data: Data
private var dataComplete: Bool
@ -107,15 +107,15 @@ private final class AnimatedStickerCachedFrameSource: AnimatedStickerFrameSource
let width: Int
let bytesPerRow: Int
let height: Int
let frameRate: Int
let frameCount: Int
public let frameRate: Int
public let frameCount: Int
private var frameIndex: Int
private let initialOffset: Int
private var offset: Int
var decodeBuffer: Data
var frameBuffer: Data
init?(queue: Queue, data: Data, complete: Bool, notifyUpdated: @escaping () -> Void) {
public init?(queue: Queue, data: Data, complete: Bool, notifyUpdated: @escaping () -> Void) {
self.queue = queue
self.data = data
self.dataComplete = complete
@ -179,7 +179,7 @@ private final class AnimatedStickerCachedFrameSource: AnimatedStickerFrameSource
assert(self.queue.isCurrent())
}
func takeFrame() -> AnimatedStickerFrame? {
public func takeFrame() -> AnimatedStickerFrame? {
var frameData: Data?
var isLastFrame = false
@ -259,7 +259,7 @@ private final class AnimatedStickerCachedFrameSource: AnimatedStickerFrameSource
self.dataComplete = complete
}
func skipToEnd() {
public func skipToEnd() {
}
}
@ -310,13 +310,13 @@ private final class AnimatedStickerDirectFrameSource: AnimatedStickerFrameSource
}
}
private final class AnimatedStickerFrameQueue {
public final class AnimatedStickerFrameQueue {
private let queue: Queue
private let length: Int
private let source: AnimatedStickerFrameSource
private var frames: [AnimatedStickerFrame] = []
init(queue: Queue, length: Int, source: AnimatedStickerFrameSource) {
public init(queue: Queue, length: Int, source: AnimatedStickerFrameSource) {
self.queue = queue
self.length = length
self.source = source
@ -326,7 +326,7 @@ private final class AnimatedStickerFrameQueue {
assert(self.queue.isCurrent())
}
func take() -> AnimatedStickerFrame? {
public func take() -> AnimatedStickerFrame? {
if self.frames.isEmpty {
if let frame = self.source.takeFrame() {
self.frames.append(frame)
@ -340,7 +340,7 @@ private final class AnimatedStickerFrameQueue {
}
}
func generateFramesIfNeeded() {
public func generateFramesIfNeeded() {
if self.frames.isEmpty {
if let frame = self.source.takeFrame() {
self.frames.append(frame)

View File

@ -2,7 +2,7 @@ import Foundation
import SwiftSignalKit
import AsyncDisplayKit
enum AnimationRendererFrameType {
public enum AnimationRendererFrameType {
case argb
case yuva
}

View File

@ -7,6 +7,13 @@ filegroup(
visibility = ["//visibility:public"],
)
filegroup(
name = "LegacyComponentsAssets",
srcs = glob(["LegacyImages.xcassets/**"]),
visibility = ["//visibility:public"],
)
objc_library(
name = "LegacyComponents",
enable_modules = True,

View File

@ -0,0 +1,6 @@
{
"info" : {
"version" : 1,
"author" : "xcode"
}
}

View File

@ -0,0 +1,12 @@
{
"images" : [
{
"filename" : "ic_editor_addsticker.pdf",
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@ -0,0 +1,12 @@
{
"images" : [
{
"filename" : "ic_editor_addtext.pdf",
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@ -0,0 +1,12 @@
{
"images" : [
{
"filename" : "ic_editor_tools.pdf",
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@ -0,0 +1,12 @@
{
"images" : [
{
"filename" : "ic_editor_frame.pdf",
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@ -0,0 +1,12 @@
{
"images" : [
{
"filename" : "ic_editor_blur.pdf",
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@ -0,0 +1,12 @@
{
"images" : [
{
"filename" : "ic_editor_brushtype.pdf",
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@ -0,0 +1,12 @@
{
"images" : [
{
"filename" : "ic_editor_close (2).pdf",
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@ -0,0 +1,12 @@
{
"images" : [
{
"filename" : "ic_editor_check (2).pdf",
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@ -0,0 +1,9 @@
{
"info" : {
"author" : "xcode",
"version" : 1
},
"properties" : {
"provides-namespace" : true
}
}

View File

@ -0,0 +1,12 @@
{
"images" : [
{
"filename" : "ic_editor_crop.pdf",
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@ -0,0 +1,12 @@
{
"images" : [
{
"filename" : "ic_editor_curves.pdf",
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@ -0,0 +1,12 @@
{
"images" : [
{
"filename" : "ic_editor_brush.pdf",
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@ -0,0 +1,12 @@
{
"images" : [
{
"filename" : "ic_editor_eracer.pdf",
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@ -0,0 +1,12 @@
{
"images" : [
{
"filename" : "ic_editor_eyedropper.pdf",
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@ -0,0 +1,12 @@
{
"images" : [
{
"filename" : "ic_editor_flip.pdf",
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@ -0,0 +1,12 @@
{
"images" : [
{
"filename" : "ic_editor_font.pdf",
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@ -0,0 +1,12 @@
{
"images" : [
{
"filename" : "ic_editor_muted.pdf",
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@ -0,0 +1,12 @@
{
"images" : [
{
"filename" : "ic_editor_play.pdf",
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@ -0,0 +1,12 @@
{
"images" : [
{
"filename" : "send.pdf",
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@ -0,0 +1,12 @@
{
"images" : [
{
"filename" : "ic_editor_rotate.pdf",
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@ -0,0 +1,12 @@
{
"images" : [
{
"filename" : "ic_editor_tint.pdf",
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@ -0,0 +1,12 @@
{
"images" : [
{
"filename" : "ic_editor_undo.pdf",
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@ -0,0 +1,12 @@
{
"images" : [
{
"filename" : "ic_editor_unmuted.pdf",
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@ -264,6 +264,8 @@
#import <LegacyComponents/TGPhotoMaskPosition.h>
#import <LegacyComponents/TGPhotoPaintEntity.h>
#import <LegacyComponents/TGPhotoPaintStickerEntity.h>
#import <LegacyComponents/TGPhotoPaintTextEntity.h>
#import <LegacyComponents/TGPhotoPaintStickersContext.h>
#import <LegacyComponents/TGPhotoToolbarView.h>
#import <LegacyComponents/TGPhotoVideoEditor.h>
#import <LegacyComponents/TGPluralization.h>

View File

@ -10,6 +10,7 @@
@class TGViewController;
@class TGAttachmentCameraView;
@protocol TGModernGalleryTransitionHostScrollView;
@protocol TGPhotoPaintStickersContext;
@interface TGAttachmentCarouselCollectionView : UICollectionView
@ -22,6 +23,7 @@
@property (nonatomic, readonly) TGMediaSelectionContext *selectionContext;
@property (nonatomic, readonly) TGMediaEditingContext *editingContext;
@property (nonatomic, strong) TGSuggestionContext *suggestionContext;
@property (nonatomic, strong) id<TGPhotoPaintStickersContext> stickersContext;
@property (nonatomic) bool allowCaptions;
@property (nonatomic) bool allowCaptionEntities;
@property (nonatomic) bool inhibitDocumentCaptions;

View File

@ -9,6 +9,8 @@
@class TGMediaAssetsPickerController;
@class TGViewController;
@protocol TGPhotoPaintStickersContext;
typedef enum
{
TGMediaAssetsControllerSendMediaIntent,
@ -49,6 +51,7 @@ typedef enum
@property (nonatomic, readonly) TGMediaEditingContext *editingContext;
@property (nonatomic, readonly) TGMediaSelectionContext *selectionContext;
@property (nonatomic, strong) TGSuggestionContext *suggestionContext;
@property (nonatomic, strong) id<TGPhotoPaintStickersContext> stickersContext;
@property (nonatomic, assign) bool localMediaCacheEnabled;
@property (nonatomic, assign) bool captionsEnabled;
@property (nonatomic, assign) bool allowCaptionEntities;

View File

@ -81,7 +81,8 @@
- (SSignal *)timersUpdatedSignal;
- (UIImage *)paintingImageForItem:(NSObject<TGMediaEditableItem> *)item;
- (bool)setPaintingData:(NSData *)data image:(UIImage *)image forItem:(NSObject<TGMediaEditableItem> *)item dataUrl:(NSURL **)dataOutUrl imageUrl:(NSURL **)imageOutUrl forVideo:(bool)video;
- (UIImage *)stillPaintingImageForItem:(NSObject<TGMediaEditableItem> *)item;
- (bool)setPaintingData:(NSData *)data image:(UIImage *)image stillImage:(UIImage *)image forItem:(NSObject<TGMediaEditableItem> *)item dataUrl:(NSURL **)dataOutUrl imageUrl:(NSURL **)imageOutUrl forVideo:(bool)video;
- (void)clearPaintingData;
- (SSignal *)facesForItem:(NSObject<TGMediaEditableItem> *)item;

View File

@ -8,6 +8,8 @@
@class TGMediaPickerSelectionGestureRecognizer;
@class TGMediaAssetsPallete;
@protocol TGPhotoPaintStickersContext;
@interface TGMediaPickerController : TGViewController <UICollectionViewDataSource, UICollectionViewDelegate, UICollectionViewDelegateFlowLayout>
{
TGMediaPickerLayoutMetrics *_layoutMetrics;
@ -18,6 +20,7 @@
}
@property (nonatomic, strong) TGSuggestionContext *suggestionContext;
@property (nonatomic, strong) id<TGPhotoPaintStickersContext> stickersContext;
@property (nonatomic, assign) bool localMediaCacheEnabled;
@property (nonatomic, assign) bool captionsEnabled;
@property (nonatomic, assign) bool allowCaptionEntities;

View File

@ -15,6 +15,8 @@
@class TGMediaSelectionContext;
@protocol TGMediaSelectableItem;
@protocol TGPhotoPaintStickersContext;
@class TGSuggestionContext;
@interface TGMediaPickerGalleryModel : TGModernGalleryModel
@ -44,6 +46,7 @@
@property (nonatomic, readonly) TGMediaSelectionContext *selectionContext;
@property (nonatomic, strong) TGSuggestionContext *suggestionContext;
@property (nonatomic, strong) id<TGPhotoPaintStickersContext> stickersContext;
- (instancetype)initWithContext:(id<LegacyComponentsContext>)context items:(NSArray *)items focusItem:(id<TGModernGalleryItem>)focusItem selectionContext:(TGMediaSelectionContext *)selectionContext editingContext:(TGMediaEditingContext *)editingContext hasCaptions:(bool)hasCaptions allowCaptionEntities:(bool)allowCaptionEntities hasTimer:(bool)hasTimer onlyCrop:(bool)onlyCrop inhibitDocumentCaptions:(bool)inhibitDocumentCaptions hasSelectionPanel:(bool)hasSelectionPanel hasCamera:(bool)hasCamera recipientName:(NSString *)recipientName;

View File

@ -11,6 +11,8 @@
@class TGMediaAssetFetchResult;
@class TGMediaAssetMomentList;
@protocol TGPhotoPaintStickersContext;
@interface TGMediaPickerModernGalleryMixin : NSObject
@property (nonatomic, weak, readonly) TGMediaPickerGalleryModel *galleryModel;
@ -29,9 +31,9 @@
@property (nonatomic, copy) void (^presentScheduleController)(void (^)(int32_t));
- (instancetype)initWithContext:(id<LegacyComponentsContext>)context item:(id)item fetchResult:(TGMediaAssetFetchResult *)fetchResult parentController:(TGViewController *)parentController thumbnailImage:(UIImage *)thumbnailImage selectionContext:(TGMediaSelectionContext *)selectionContext editingContext:(TGMediaEditingContext *)editingContext suggestionContext:(TGSuggestionContext *)suggestionContext hasCaptions:(bool)hasCaptions allowCaptionEntities:(bool)allowCaptionEntities hasTimer:(bool)hasTimer onlyCrop:(bool)onlyCrop inhibitDocumentCaptions:(bool)inhibitDocumentCaptions inhibitMute:(bool)inhibitMute asFile:(bool)asFile itemsLimit:(NSUInteger)itemsLimit recipientName:(NSString *)recipientName hasSilentPosting:(bool)hasSilentPosting hasSchedule:(bool)hasSchedule reminder:(bool)reminder;
- (instancetype)initWithContext:(id<LegacyComponentsContext>)context item:(id)item fetchResult:(TGMediaAssetFetchResult *)fetchResult parentController:(TGViewController *)parentController thumbnailImage:(UIImage *)thumbnailImage selectionContext:(TGMediaSelectionContext *)selectionContext editingContext:(TGMediaEditingContext *)editingContext suggestionContext:(TGSuggestionContext *)suggestionContext hasCaptions:(bool)hasCaptions allowCaptionEntities:(bool)allowCaptionEntities hasTimer:(bool)hasTimer onlyCrop:(bool)onlyCrop inhibitDocumentCaptions:(bool)inhibitDocumentCaptions inhibitMute:(bool)inhibitMute asFile:(bool)asFile itemsLimit:(NSUInteger)itemsLimit recipientName:(NSString *)recipientName hasSilentPosting:(bool)hasSilentPosting hasSchedule:(bool)hasSchedule reminder:(bool)reminder stickersContext:(id<TGPhotoPaintStickersContext>)stickersContext;
- (instancetype)initWithContext:(id<LegacyComponentsContext>)context item:(id)item momentList:(TGMediaAssetMomentList *)momentList parentController:(TGViewController *)parentController thumbnailImage:(UIImage *)thumbnailImage selectionContext:(TGMediaSelectionContext *)selectionContext editingContext:(TGMediaEditingContext *)editingContext suggestionContext:(TGSuggestionContext *)suggestionContext hasCaptions:(bool)hasCaptions allowCaptionEntities:(bool)allowCaptionEntities hasTimer:(bool)hasTimer onlyCrop:(bool)onlyCrop inhibitDocumentCaptions:(bool)inhibitDocumentCaptions inhibitMute:(bool)inhibitMute asFile:(bool)asFile itemsLimit:(NSUInteger)itemsLimit hasSilentPosting:(bool)hasSilentPosting hasSchedule:(bool)hasSchedule reminder:(bool)reminder;
- (instancetype)initWithContext:(id<LegacyComponentsContext>)context item:(id)item momentList:(TGMediaAssetMomentList *)momentList parentController:(TGViewController *)parentController thumbnailImage:(UIImage *)thumbnailImage selectionContext:(TGMediaSelectionContext *)selectionContext editingContext:(TGMediaEditingContext *)editingContext suggestionContext:(TGSuggestionContext *)suggestionContext hasCaptions:(bool)hasCaptions allowCaptionEntities:(bool)allowCaptionEntities hasTimer:(bool)hasTimer onlyCrop:(bool)onlyCrop inhibitDocumentCaptions:(bool)inhibitDocumentCaptions inhibitMute:(bool)inhibitMute asFile:(bool)asFile itemsLimit:(NSUInteger)itemsLimit hasSilentPosting:(bool)hasSilentPosting hasSchedule:(bool)hasSchedule reminder:(bool)reminder stickersContext:(id<TGPhotoPaintStickersContext>)stickersContext;
- (void)present;
- (void)updateWithFetchResult:(TGMediaAssetFetchResult *)fetchResult;

View File

@ -12,11 +12,12 @@
@end
@protocol TGPhotoPaintEntityRenderer;
@interface TGMediaVideoConverter : NSObject
+ (SSignal *)convertAVAsset:(AVAsset *)avAsset adjustments:(TGMediaVideoEditAdjustments *)adjustments watcher:(TGMediaVideoFileWatcher *)watcher;
+ (SSignal *)convertAVAsset:(AVAsset *)avAsset adjustments:(TGMediaVideoEditAdjustments *)adjustments watcher:(TGMediaVideoFileWatcher *)watcher inhibitAudio:(bool)inhibitAudio;
+ (SSignal *)convertAVAsset:(AVAsset *)avAsset adjustments:(TGMediaVideoEditAdjustments *)adjustments watcher:(TGMediaVideoFileWatcher *)watcher 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;
+ (NSUInteger)estimatedSizeForPreset:(TGMediaVideoConversionPreset)preset duration:(NSTimeInterval)duration hasAudio:(bool)hasAudio;

View File

@ -7,4 +7,6 @@
@property (nonatomic, copy) void (^singleTapped)();
@property (nonatomic, copy) void (^doubleTapped)(CGPoint point);
- (instancetype)initWithFrame:(CGRect)frame hasDoubleTap:(bool)hasDoubleTap;
@end

View File

@ -16,7 +16,11 @@
@property (nonatomic, readonly) NSData *data;
@property (nonatomic, readonly) UIImage *image;
+ (instancetype)dataWithPaintingData:(NSData *)data image:(UIImage *)image entities:(NSArray *)entities undoManager:(TGPaintUndoManager *)undoManager;
@property (nonatomic, readonly) UIImage *stillImage;
+ (instancetype)dataWithPaintingData:(NSData *)data image:(UIImage *)image stillImage:(UIImage *)stillImage entities:(NSArray *)entities undoManager:(TGPaintUndoManager *)undoManager;
+ (instancetype)dataWithPaintingImagePath:(NSString *)imagePath entities:(NSArray *)entities;
+ (instancetype)dataWithPaintingImagePath:(NSString *)imagePath;

View File

@ -11,6 +11,8 @@
@class TGSuggestionContext;
@class TGPhotoEditorController;
@protocol TGPhotoPaintStickersContext;
typedef enum {
TGPhotoEditorControllerGenericIntent = 0,
TGPhotoEditorControllerAvatarIntent = (1 << 0),
@ -24,6 +26,7 @@ typedef enum {
@property (nonatomic, strong) TGSuggestionContext *suggestionContext;
@property (nonatomic, strong) TGMediaEditingContext *editingContext;
@property (nonatomic, strong) id<TGPhotoPaintStickersContext> stickersContext;
@property (nonatomic, copy) UIView *(^beginTransitionIn)(CGRect *referenceFrame, UIView **parentView);
@property (nonatomic, copy) void (^finishedTransitionIn)(void);

View File

@ -18,7 +18,6 @@
+ (UIColor *)editorButtonSelectionBackgroundColor;
+ (UIImage *)captionIcon;
+ (UIImage *)cropIcon;
+ (UIImage *)toolsIcon;
+ (UIImage *)rotateIcon;

View File

@ -7,6 +7,7 @@
}
@property (nonatomic, assign) NSInteger uuid;
@property (nonatomic, readonly) bool animated;
@property (nonatomic, assign) CGPoint position;
@property (nonatomic, assign) CGFloat angle;
@property (nonatomic, assign) CGFloat scale;

View File

@ -4,11 +4,11 @@
@interface TGPhotoPaintStickerEntity : TGPhotoPaintEntity
@property (nonatomic, readonly) TGDocumentMediaAttachment *document;
@property (nonatomic, readonly) NSData *document;
@property (nonatomic, readonly) NSString *emoji;
@property (nonatomic, readonly) CGSize baseSize;
- (instancetype)initWithDocument:(TGDocumentMediaAttachment *)document baseSize:(CGSize)baseSize;
- (instancetype)initWithDocument:(id)document baseSize:(CGSize)baseSize animated:(bool)animated;
- (instancetype)initWithEmoji:(NSString *)emoji;
@end

View File

@ -0,0 +1,25 @@
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
#import <CoreMedia/CoreMedia.h>
@class TGPaintingData;
@protocol TGPhotoPaintEntityRenderer <NSObject>
- (void)entitiesForTime:(CMTime)time size:(CGSize)size completion:(void(^)(NSArray<CIImage *> *))completion;
@end
@protocol TGPhotoPaintStickerRenderView <NSObject>
- (UIImage *)image;
@end
@protocol TGPhotoPaintStickersContext <NSObject>
- (UIView<TGPhotoPaintStickerRenderView> *)stickerViewForDocument:(id)document;
@property (nonatomic, copy) void(^presentStickersController)(void(^)(id, bool, UIView *, CGRect));
@end

View File

@ -1,6 +1,7 @@
#import <LegacyComponents/TGPhotoPaintEntity.h>
#import "TGPaintSwatch.h"
#import "TGPhotoPaintFont.h"
@class TGPaintSwatch;
@class TGPhotoPaintFont;
@interface TGPhotoPaintTextEntity : TGPhotoPaintEntity
@ -11,6 +12,8 @@
@property (nonatomic, assign) CGFloat maxWidth;
@property (nonatomic, assign) bool stroke;
@property (nonatomic, strong) UIImage *renderImage;
- (instancetype)initWithText:(NSString *)text font:(TGPhotoPaintFont *)font swatch:(TGPaintSwatch *)swatch baseFontSize:(CGFloat)baseFontSize maxWidth:(CGFloat)maxWidth stroke:(bool)stroke;
@end

View File

@ -3,9 +3,9 @@
typedef NS_OPTIONS(NSUInteger, TGPhotoEditorTab) {
TGPhotoEditorNoneTab = 0,
TGPhotoEditorCropTab = 1 << 0,
TGPhotoEditorStickerTab = 1 << 1,
TGPhotoEditorPaintTab = 1 << 2,
TGPhotoEditorEraserTab = 1 << 3,
TGPhotoEditorPaintTab = 1 << 1,
TGPhotoEditorEraserTab = 1 << 2,
TGPhotoEditorStickerTab = 1 << 3,
TGPhotoEditorTextTab = 1 << 4,
TGPhotoEditorToolsTab = 1 << 5,
TGPhotoEditorRotateTab = 1 << 6,

View File

@ -57,4 +57,6 @@ typedef struct GPUTextureOptions {
- (NSUInteger)bytesPerRow;
- (GLubyte *)byteBuffer;
+ (void)setMark:(BOOL)mark;
@end

View File

@ -33,13 +33,18 @@ void dataProviderUnlockCallback (void *info, const void *data, size_t size);
#pragma mark -
#pragma mark Initialization and teardown
static BOOL mark = false;
+ (void)setMark:(BOOL)mark_ {
mark = mark_;
}
- (id)initWithSize:(CGSize)framebufferSize textureOptions:(GPUTextureOptions)fboTextureOptions onlyTexture:(BOOL)onlyGenerateTexture
{
if (!(self = [super init]))
{
return nil;
}
_mark = mark;
_textureOptions = fboTextureOptions;
_size = framebufferSize;
framebufferReferenceCount = 0;
@ -67,7 +72,7 @@ void dataProviderUnlockCallback (void *info, const void *data, size_t size);
{
return nil;
}
_mark = mark;
GPUTextureOptions defaultTextureOptions;
defaultTextureOptions.minFilter = GL_LINEAR;
defaultTextureOptions.magFilter = GL_LINEAR;
@ -89,6 +94,7 @@ void dataProviderUnlockCallback (void *info, const void *data, size_t size);
- (id)initWithSize:(CGSize)framebufferSize
{
_mark = mark;
GPUTextureOptions defaultTextureOptions;
defaultTextureOptions.minFilter = GL_LINEAR;
defaultTextureOptions.magFilter = GL_LINEAR;
@ -136,10 +142,8 @@ void dataProviderUnlockCallback (void *info, const void *data, size_t size);
glGenFramebuffers(1, &framebuffer);
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
// By default, all framebuffers on iOS 5.0+ devices are backed by texture caches, using one shared cache
if ([GPUImageContext supportsFastTextureUpload])
{
#if TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE
CVOpenGLESTextureCacheRef coreVideoTextureCache = [[GPUImageContext sharedImageProcessingContext] coreVideoTextureCache];
// Code originally sourced from http://allmybrain.com/2011/12/08/rendering-to-a-texture-with-ios-5-texture-cache-api/
@ -180,7 +184,6 @@ void dataProviderUnlockCallback (void *info, const void *data, size_t size);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, _textureOptions.wrapT);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, CVOpenGLESTextureGetName(renderTexture), 0);
#endif
}
else
{
@ -275,8 +278,10 @@ void dataProviderUnlockCallback (void *info, const void *data, size_t size);
if (framebufferReferenceCount < 1)
{
[[GPUImageContext sharedFramebufferCache] returnFramebufferToCache:self];
} else if (framebufferReferenceCount == 1) {
fixer = [TGTimerTarget scheduledMainThreadTimerWithTarget:self action:@selector(fixTick) interval:0.3 repeat:false];
[fixer invalidate];
fixer = nil;
} else if (framebufferReferenceCount == 1 && self.mark) {
fixer = [TGTimerTarget scheduledMainThreadTimerWithTarget:self action:@selector(fixTick) interval:0.35 repeat:false];
}
}
@ -336,7 +341,6 @@ void dataProviderUnlockCallback (void *info, __unused const void *data, __unused
CGDataProviderRef dataProvider = NULL;
if ([GPUImageContext supportsFastTextureUpload])
{
#if TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE
NSUInteger paddedWidthOfImage = (NSUInteger)(CVPixelBufferGetBytesPerRow(renderTarget) / 4.0);
NSUInteger paddedBytesForImage = paddedWidthOfImage * (int)_size.height * 4;
@ -346,8 +350,6 @@ void dataProviderUnlockCallback (void *info, __unused const void *data, __unused
rawImagePixels = (GLubyte *)CVPixelBufferGetBaseAddress(renderTarget);
dataProvider = CGDataProviderCreateWithData((__bridge_retained void*)self, rawImagePixels, paddedBytesForImage, dataProviderUnlockCallback);
[[GPUImageContext sharedFramebufferCache] addFramebufferToActiveImageCaptureList:self]; // In case the framebuffer is swapped out on the filter, need to have a strong reference to it somewhere for it to hang on while the image is in existence
#else
#endif
}
else
{
@ -362,10 +364,7 @@ void dataProviderUnlockCallback (void *info, __unused const void *data, __unused
if ([GPUImageContext supportsFastTextureUpload])
{
#if TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE
cgImageFromBytes = CGImageCreate((int)_size.width, (int)_size.height, 8, 32, CVPixelBufferGetBytesPerRow(renderTarget), defaultRGBColorSpace, kCGBitmapByteOrder32Little | kCGImageAlphaPremultipliedFirst, dataProvider, NULL, NO, kCGRenderingIntentDefault);
#else
#endif
}
else
{

View File

@ -94,7 +94,6 @@
{
// Nothing in the cache, create a new framebuffer to use
framebufferFromCache = [[GPUImageFramebuffer alloc] initWithSize:framebufferSize textureOptions:textureOptions onlyTexture:onlyTexture];
framebufferFromCache.mark = mark;
}
else
{
@ -120,7 +119,6 @@
if (framebufferFromCache == nil)
{
framebufferFromCache = [[GPUImageFramebuffer alloc] initWithSize:framebufferSize textureOptions:textureOptions onlyTexture:onlyTexture];
framebufferFromCache.mark = mark;
}
}
});

View File

@ -1,21 +1,7 @@
#import "GPUImageContext.h"
#import "GPUImageFramebuffer.h"
#if TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE
#import <UIKit/UIKit.h>
#else
// For now, just redefine this on the Mac
typedef NS_ENUM(NSInteger, UIImageOrientation) {
UIImageOrientationUp, // default orientation
UIImageOrientationDown, // 180 deg rotation
UIImageOrientationLeft, // 90 deg CCW
UIImageOrientationRight, // 90 deg CW
UIImageOrientationUpMirrored, // as above but image mirrored along other axis. horizontal flip
UIImageOrientationDownMirrored, // horizontal flip
UIImageOrientationLeftMirrored, // vertical flip
UIImageOrientationRightMirrored, // vertical flip
};
#endif
void runOnMainQueueWithoutDeadlocking(void (^block)(void));
void runSynchronouslyOnVideoProcessingQueue(void (^block)(void));
@ -24,17 +10,6 @@ void runSynchronouslyOnContextQueue(GPUImageContext *context, void (^block)(void
void runAsynchronouslyOnContextQueue(GPUImageContext *context, void (^block)(void));
void reportAvailableMemoryForGPUImage(NSString *tag);
/** GPUImage's base source object
Images or frames of video are uploaded from source objects, which are subclasses of GPUImageOutput. These include:
- GPUImageVideoCamera (for live video from an iOS camera)
- GPUImageStillCamera (for taking photos with the camera)
- GPUImagePicture (for still images)
- GPUImageMovie (for movies)
Source objects upload still image frames to OpenGL ES as textures, then hand those textures off to the next objects in the processing chain.
*/
@interface GPUImageOutput : NSObject
{
GPUImageFramebuffer *outputFramebuffer;
@ -56,7 +31,6 @@ void reportAvailableMemoryForGPUImage(NSString *tag);
@property(nonatomic) BOOL enabled;
@property(readwrite, nonatomic) GPUTextureOptions outputTextureOptions;
/// @name Managing targets
- (void)setInputFramebufferForTarget:(id<GPUImageInput>)target atIndex:(NSInteger)inputTextureIndex;
- (GPUImageFramebuffer *)framebufferForOutput;
- (void)removeOutputFramebuffer;
@ -106,15 +80,8 @@ void reportAvailableMemoryForGPUImage(NSString *tag);
- (void)useNextFrameForImageCapture;
- (CGImageRef)newCGImageFromCurrentlyProcessedOutput;
// Platform-specific image output methods
// If you're trying to use these methods, remember that you need to set -useNextFrameForImageCapture before running -processImage or running video and calling any of these methods, or you will get a nil image
#if TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE
- (UIImage *)imageFromCurrentFramebuffer;
- (UIImage *)imageFromCurrentFramebufferWithOrientation:(UIImageOrientation)imageOrientation;
#else
- (NSImage *)imageFromCurrentFramebuffer;
- (NSImage *)imageFromCurrentFramebufferWithOrientation:(UIImageOrientation)imageOrientation;
#endif
- (BOOL)providesMonochromeOutput;

View File

@ -0,0 +1,16 @@
#import "GPUImageOutput.h"
#import <CoreImage/CoreImage.h>
@interface GPUImageTextureInput : GPUImageOutput
{
CGSize textureSize;
}
- (instancetype)initWithTexture:(GLuint)newInputTexture size:(CGSize)newTextureSize;
- (instancetype)initWithCIImage:(CIImage *)ciImage;
- (void)processTextureWithFrameTime:(CMTime)frameTime synchronous:(bool)synchronous;
- (CGSize)textureSize;
@end

View File

@ -0,0 +1,94 @@
#import "GPUImageTextureInput.h"
@implementation GPUImageTextureInput
#pragma mark -
#pragma mark Initialization and teardown
- (instancetype)initWithTexture:(GLuint)newInputTexture size:(CGSize)newTextureSize
{
if (!(self = [super init]))
{
return nil;
}
runSynchronouslyOnVideoProcessingQueue(^{
[GPUImageContext useImageProcessingContext];
});
textureSize = newTextureSize;
runSynchronouslyOnVideoProcessingQueue(^{
outputFramebuffer = [[GPUImageFramebuffer alloc] initWithSize:newTextureSize overriddenTexture:newInputTexture];
});
return self;
}
- (instancetype)initWithCIImage:(CIImage *)ciImage
{
EAGLContext *context = [[GPUImageContext sharedImageProcessingContext] context];
[EAGLContext setCurrentContext:[[GPUImageContext sharedImageProcessingContext] context]];
GLsizei backingWidth = ciImage.extent.size.width;
GLsizei backingHeight = ciImage.extent.size.height;
GLuint outputTexture, defaultFramebuffer;
glActiveTexture(GL_TEXTURE0);
glGenTextures(1, &outputTexture);
glBindTexture(GL_TEXTURE_2D, outputTexture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glBindTexture(GL_TEXTURE_2D, 0);
glActiveTexture(GL_TEXTURE1);
glGenFramebuffers(1, &defaultFramebuffer);
glBindFramebuffer(GL_FRAMEBUFFER, defaultFramebuffer);
glBindTexture(GL_TEXTURE_2D, outputTexture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, backingWidth, backingHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, outputTexture, 0);
NSAssert(glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE, @"Incomplete filter FBO: %d", glCheckFramebufferStatus(GL_FRAMEBUFFER));
glBindTexture(GL_TEXTURE_2D, 0);
ciImage = [ciImage imageByApplyingTransform:CGAffineTransformConcat(CGAffineTransformMakeScale(1.0f, -1.0f), CGAffineTransformMakeTranslation(0.0f, ciImage.extent.size.height))];
CIContext *ciContext = [CIContext contextWithEAGLContext:context options:@{kCIContextWorkingColorSpace: [NSNull null]}];
[ciContext drawImage:ciImage inRect:ciImage.extent fromRect:ciImage.extent];
if (self = [self initWithTexture:outputTexture size:ciImage.extent.size]) {
textureSize = ciImage.extent.size;
}
return self;
}
- (void)processTextureWithFrameTime:(CMTime)frameTime synchronous:(bool)synchronous
{
void (^block)(void) = ^
{
for (id<GPUImageInput> currentTarget in targets)
{
NSInteger indexOfObject = [targets indexOfObject:currentTarget];
NSInteger targetTextureIndex = [[targetTextureIndices objectAtIndex:indexOfObject] integerValue];
[currentTarget setInputSize:textureSize atIndex:targetTextureIndex];
[currentTarget setInputFramebuffer:outputFramebuffer atIndex:targetTextureIndex];
[currentTarget newFrameReadyAtTime:frameTime atIndex:targetTextureIndex];
}
};
if (synchronous)
runSynchronouslyOnVideoProcessingQueue(block);
else
runAsynchronouslyOnVideoProcessingQueue(block);
}
- (CGSize)textureSize {
return textureSize;
}
@end

View File

@ -0,0 +1,24 @@
#import <Foundation/Foundation.h>
#import <CoreImage/CoreImage.h>
#import "GPUImageContext.h"
@protocol GPUImageTextureOutputDelegate;
@interface GPUImageTextureOutput : NSObject <GPUImageInput>
{
GPUImageFramebuffer *firstInputFramebuffer;
}
@property(readwrite, unsafe_unretained, nonatomic) id<GPUImageTextureOutputDelegate> delegate;
@property(readonly) GLuint texture;
@property(nonatomic) BOOL enabled;
- (CIImage *)CIImageWithSize:(CGSize)size;
- (void)doneWithTexture;
@end
@protocol GPUImageTextureOutputDelegate
- (void)newFrameReadyFromTextureOutput:(GPUImageTextureOutput *)callbackTextureOutput;
@end

View File

@ -0,0 +1,91 @@
#import "GPUImageTextureOutput.h"
@implementation GPUImageTextureOutput
@synthesize delegate = _delegate;
@synthesize texture = _texture;
@synthesize enabled;
#pragma mark -
#pragma mark Initialization and teardown
- (id)init;
{
if (!(self = [super init]))
{
return nil;
}
self.enabled = YES;
return self;
}
- (void)doneWithTexture;
{
[firstInputFramebuffer unlock];
}
#pragma mark -
#pragma mark GPUImageInput protocol
- (void)newFrameReadyAtTime:(CMTime)frameTime atIndex:(NSInteger)textureIndex;
{
[_delegate newFrameReadyFromTextureOutput:self];
}
- (NSInteger)nextAvailableTextureIndex;
{
return 0;
}
- (CIImage *)CIImageWithSize:(CGSize)size
{
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
CIImage *image = [[CIImage alloc] initWithTexture:self.texture size:size flipped:true colorSpace:colorSpace];
CGColorSpaceRelease(colorSpace);
return image;
}
// TODO: Deal with the fact that the texture changes regularly as a result of the caching
- (void)setInputFramebuffer:(GPUImageFramebuffer *)newInputFramebuffer atIndex:(NSInteger)textureIndex;
{
firstInputFramebuffer = newInputFramebuffer;
[firstInputFramebuffer lock];
_texture = [firstInputFramebuffer texture];
}
- (void)setInputRotation:(GPUImageRotationMode)newInputRotation atIndex:(NSInteger)textureIndex;
{
}
- (void)setInputSize:(CGSize)newSize atIndex:(NSInteger)textureIndex;
{
}
- (CGSize)maximumOutputSize;
{
return CGSizeZero;
}
- (void)endProcessing
{
}
- (BOOL)shouldIgnoreUpdatesToThisTarget;
{
return NO;
}
- (BOOL)wantsMonochromeInput;
{
return NO;
}
- (void)setCurrentlyReceivingMonochromeInput:(BOOL)newValue;
{
}
@end

View File

@ -152,5 +152,9 @@ UIImage *TGComponentsImageNamed(NSString *name) {
}
NSString *TGComponentsPathForResource(NSString *name, NSString *type) {
return [resourcesBundle() pathForResource:name ofType:type];
NSBundle *bundle = resourcesBundle();
if (bundle == nil) {
bundle = getAppBundle();
}
return [bundle pathForResource:name ofType:type];
}

View File

@ -37,11 +37,13 @@
- (void)setImage:(UIImage *)image forCropRect:(CGRect)cropRect cropRotation:(CGFloat)cropRotation cropOrientation:(UIImageOrientation)cropOrientation cropMirrored:(bool)cropMirrored fullSize:(bool)fullSize;
- (void)setVideoAsset:(AVAsset *)asset;
- (void)setCIImage:(CIImage *)ciImage;
- (void)processAnimated:(bool)animated completion:(void (^)(void))completion;
- (void)createResultImageWithCompletion:(void (^)(UIImage *image))completion;
- (UIImage *)currentResultImage;
- (CIImage *)currentResultCIImage;
- (bool)hasDefaultCropping;

View File

@ -10,6 +10,9 @@
#import "PGPhotoEditorView.h"
#import "PGPhotoEditorPicture.h"
#import "GPUImageTextureInput.h"
#import "GPUImageTextureOutput.h"
#import <LegacyComponents/PGPhotoEditorValues.h>
#import <LegacyComponents/TGVideoEditAdjustments.h>
#import <LegacyComponents/TGPaintingData.h>
@ -44,6 +47,8 @@
NSArray *_currentProcessChain;
GPUImageOutput <GPUImageInput> *_finalFilter;
GPUImageTextureOutput *_textureOutput;
PGPhotoHistogram *_currentHistogram;
PGPhotoHistogramGenerator *_histogramGenerator;
@ -167,6 +172,21 @@
_fullSize = true;
}
- (void)setCIImage:(CIImage *)ciImage {
[_toolComposer invalidate];
_currentProcessChain = nil;
[_currentInput removeAllTargets];
GPUImageTextureInput *input = [[GPUImageTextureInput alloc] initWithCIImage:ciImage];
_currentInput = input;
if (_textureOutput == nil) {
_textureOutput = [[GPUImageTextureOutput alloc] init];
}
_fullSize = true;
}
#pragma mark - Properties
- (CGSize)rotatedCropSize
@ -201,7 +221,7 @@
- (void)processAnimated:(bool)animated capture:(bool)capture synchronous:(bool)synchronous completion:(void (^)(void))completion
{
if (self.previewOutput == nil)
if (self.previewOutput == nil && ![_currentInput isKindOfClass:[GPUImageTextureInput class]])
return;
if (self.forVideo) {
@ -210,7 +230,7 @@
[self updateProcessChain];
GPUImageOutput *currentInput = _currentInput;
if ([currentInput isKindOfClass:[PGVideoMovie class]]) {
if (!_playing) {
_playing = true;
[_videoQueue dispatch:^{
@ -219,7 +239,12 @@
}
}];
}
}];
} else if ([currentInput isKindOfClass:[GPUImageTextureInput class]]) {
[(GPUImageTextureInput *)currentInput processTextureWithFrameTime:kCMTimeZero synchronous:synchronous];
if (completion != nil)
completion();
}
} synchronous:synchronous];
return;
}
@ -281,6 +306,8 @@
}
- (void)updateProcessChain {
[GPUImageFramebuffer setMark:self.forVideo];
NSMutableArray *processChain = [NSMutableArray array];
for (PGPhotoTool *tool in _toolComposer.advancedTools)
@ -319,11 +346,18 @@
}
_finalFilter = lastFilter;
[_finalFilter addTarget:previewOutput.imageView];
if (_textureOutput != nil) {
[_finalFilter addTarget:_textureOutput];
}
if (!self.forVideo)
if (previewOutput != nil) {
[_finalFilter addTarget:previewOutput.imageView];
}
if (!self.forVideo) {
[_finalFilter addTarget:_histogramGenerator];
}
}
}
#pragma mark - Result
@ -349,6 +383,18 @@
return image;
}
- (CIImage *)currentResultCIImage {
__block CIImage *image = nil;
GPUImageOutput *currentInput = _currentInput;
[self processAnimated:false capture:false synchronous:true completion:^
{
if ([currentInput isKindOfClass:[GPUImageTextureInput class]]) {
image = [_textureOutput CIImageWithSize:[(GPUImageTextureInput *)currentInput textureSize]];
}
}];
return image;
}
#pragma mark - Editor Values
- (void)_importAdjustments:(id<TGMediaEditAdjustments>)adjustments

View File

@ -14,9 +14,9 @@ GLfloat kColorConversion601FullRangeDefault[] = {
};
GLfloat kColorConversion709Default[] = {
1.164, 1.164, 1.164,
0.0, -0.213, 2.112,
1.793, -0.533, 0.0,
1, 1, 1,
0, -.21482, 2.12798,
1.28033, -.38059, 0,
};
GLfloat *kColorConversion601 = kColorConversion601Default;
@ -124,7 +124,7 @@ NSString *const kYUVVideoRangeConversionForLAFragmentShaderString = SHADER_STRIN
#pragma mark Initialization and teardown
- (instancetype)initWithAsset:(AVAsset *)asset;
- (instancetype)initWithAsset:(AVAsset *)asset
{
if (!(self = [super init]))
{
@ -138,7 +138,7 @@ NSString *const kYUVVideoRangeConversionForLAFragmentShaderString = SHADER_STRIN
return self;
}
- (void)yuvConversionSetup;
- (void)yuvConversionSetup
{
if ([GPUImageContext supportsFastTextureUpload])
{
@ -147,7 +147,7 @@ NSString *const kYUVVideoRangeConversionForLAFragmentShaderString = SHADER_STRIN
_preferredConversion = kColorConversion709;
isFullYUVRange = YES;
yuvConversionProgram = [[GPUImageContext sharedImageProcessingContext] programForVertexShaderString:kGPUImageVertexShaderString fragmentShaderString:kYUVFullRangeConversionForLAFragmentShaderString];
yuvConversionProgram = [[GPUImageContext sharedImageProcessingContext] programForVertexShaderString:kGPUImageVertexShaderString fragmentShaderString:kYUVVideoRangeConversionForRGFragmentShaderString];
if (!yuvConversionProgram.initialized)
{
@ -224,7 +224,6 @@ NSString *const kYUVVideoRangeConversionForLAFragmentShaderString = SHADER_STRIN
isFullYUVRange = NO;
}
// Maybe set alwaysCopiesSampleData to NO on iOS 5.0 for faster video decoding
AVAssetReaderTrackOutput *readerVideoTrackOutput = [AVAssetReaderTrackOutput assetReaderTrackOutputWithTrack:[[self.asset tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0] outputSettings:outputSettings];
readerVideoTrackOutput.alwaysCopiesSampleData = NO;
[assetReader addOutput:readerVideoTrackOutput];
@ -486,8 +485,6 @@ NSString *const kYUVVideoRangeConversionForLAFragmentShaderString = SHADER_STRIN
}
CFAbsoluteTime startTime = CFAbsoluteTimeGetCurrent();
[GPUImageContext useImageProcessingContext];
if ([GPUImageContext supportsFastTextureUpload])
@ -510,7 +507,7 @@ NSString *const kYUVVideoRangeConversionForLAFragmentShaderString = SHADER_STRIN
glActiveTexture(GL_TEXTURE4);
if ([GPUImageContext deviceSupportsRedTextures])
{
err = CVOpenGLESTextureCacheCreateTextureFromImage(kCFAllocatorDefault, [[GPUImageContext sharedImageProcessingContext] coreVideoTextureCache], movieFrame, NULL, GL_TEXTURE_2D, GL_LUMINANCE, bufferWidth, bufferHeight, GL_LUMINANCE, GL_UNSIGNED_BYTE, 0, &luminanceTextureRef);
err = CVOpenGLESTextureCacheCreateTextureFromImage(kCFAllocatorDefault, [[GPUImageContext sharedImageProcessingContext] coreVideoTextureCache], movieFrame, NULL, GL_TEXTURE_2D, GL_RED_EXT, bufferWidth, bufferHeight, GL_RED_EXT, GL_UNSIGNED_BYTE, 0, &luminanceTextureRef);
}
else
{
@ -531,7 +528,7 @@ NSString *const kYUVVideoRangeConversionForLAFragmentShaderString = SHADER_STRIN
glActiveTexture(GL_TEXTURE5);
if ([GPUImageContext deviceSupportsRedTextures])
{
err = CVOpenGLESTextureCacheCreateTextureFromImage(kCFAllocatorDefault, [[GPUImageContext sharedImageProcessingContext] coreVideoTextureCache], movieFrame, NULL, GL_TEXTURE_2D, GL_LUMINANCE_ALPHA, bufferWidth/2, bufferHeight/2, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, 1, &chrominanceTextureRef);
err = CVOpenGLESTextureCacheCreateTextureFromImage(kCFAllocatorDefault, [[GPUImageContext sharedImageProcessingContext] coreVideoTextureCache], movieFrame, NULL, GL_TEXTURE_2D, GL_RG_EXT, bufferWidth/2, bufferHeight/2, GL_RG_EXT, GL_UNSIGNED_BYTE, 1, &chrominanceTextureRef);
}
else
{
@ -556,6 +553,8 @@ NSString *const kYUVVideoRangeConversionForLAFragmentShaderString = SHADER_STRIN
NSInteger targetTextureIndex = [[targetTextureIndices objectAtIndex:indexOfObject] integerValue];
[currentTarget setInputSize:CGSizeMake(bufferWidth, bufferHeight) atIndex:targetTextureIndex];
[currentTarget setInputFramebuffer:outputFramebuffer atIndex:targetTextureIndex];
// [currentTarget setInputRotation:kGPUImageRotateLeft atIndex:targetTextureIndex];
}
[outputFramebuffer unlock];

View File

@ -801,7 +801,7 @@ const NSUInteger TGAttachmentDisplayedAssetLimit = 500;
if ([cell isKindOfClass:[TGAttachmentAssetCell class]])
thumbnailImage = cell.imageView.image;
TGMediaPickerModernGalleryMixin *mixin = [[TGMediaPickerModernGalleryMixin alloc] initWithContext:_context item:asset fetchResult:_fetchResult parentController:self.parentController thumbnailImage:thumbnailImage selectionContext:_selectionContext editingContext:_editingContext suggestionContext:self.suggestionContext hasCaptions:(_allowCaptions && !_forProfilePhoto) allowCaptionEntities:self.allowCaptionEntities hasTimer:self.hasTimer onlyCrop:self.onlyCrop inhibitDocumentCaptions:_inhibitDocumentCaptions inhibitMute:self.inhibitMute asFile:self.asFile itemsLimit:TGAttachmentDisplayedAssetLimit recipientName:self.recipientName hasSilentPosting:self.hasSilentPosting hasSchedule:self.hasSchedule reminder:self.reminder];
TGMediaPickerModernGalleryMixin *mixin = [[TGMediaPickerModernGalleryMixin alloc] initWithContext:_context item:asset fetchResult:_fetchResult parentController:self.parentController thumbnailImage:thumbnailImage selectionContext:_selectionContext editingContext:_editingContext suggestionContext:self.suggestionContext hasCaptions:(_allowCaptions && !_forProfilePhoto) allowCaptionEntities:self.allowCaptionEntities hasTimer:self.hasTimer onlyCrop:self.onlyCrop inhibitDocumentCaptions:_inhibitDocumentCaptions inhibitMute:self.inhibitMute asFile:self.asFile itemsLimit:TGAttachmentDisplayedAssetLimit recipientName:self.recipientName hasSilentPosting:self.hasSilentPosting hasSchedule:self.hasSchedule reminder:self.reminder stickersContext:self.stickersContext];
mixin.presentScheduleController = self.presentScheduleController;
__weak TGAttachmentCarouselItemView *weakSelf = self;
mixin.thumbnailSignalForItem = ^SSignal *(id item)

View File

@ -135,7 +135,7 @@
CGRect containerFrame = self.view.bounds;
CGSize fittedSize = TGScaleToSize(_image.size, containerFrame.size);
_scrollView = [[TGModernGalleryZoomableScrollView alloc] initWithFrame:self.view.bounds];
_scrollView = [[TGModernGalleryZoomableScrollView alloc] initWithFrame:self.view.bounds hasDoubleTap:true];
_scrollView.clipsToBounds = false;
_scrollView.delegate = self;
_scrollView.showsHorizontalScrollIndicator = false;

View File

@ -42,6 +42,7 @@
TGClipboardPreviewItemView *previewItem = [[TGClipboardPreviewItemView alloc] initWithContext:context images:images];
__weak TGClipboardPreviewItemView *weakPreviewItem = previewItem;
previewItem.suggestionContext = suggestionContext;
previewItem.parentController = parentController;
previewItem.allowCaptions = hasCaption;
previewItem.hasTimer = hasTimer;

View File

@ -117,8 +117,8 @@ UIFont *TGFixedSystemFontOfSize(CGFloat size)
+ (UIFont *)roundedFontOfSize:(CGFloat)size
{
if (@available(iOSApplicationExtension 13.0, iOS 13.0, *)) {
UIFontDescriptor *descriptor = [UIFont systemFontOfSize: size].fontDescriptor;
descriptor = [descriptor fontDescriptorWithDesign: UIFontDescriptorSystemDesignRounded];
UIFontDescriptor *descriptor = [UIFont boldSystemFontOfSize: size].fontDescriptor;
descriptor = [descriptor fontDescriptorWithDesign:UIFontDescriptorSystemDesignRounded];
return [UIFont fontWithDescriptor:descriptor size:size];
} else {
return [UIFont fontWithName:@".SFCompactRounded-Semibold" size:size];

View File

@ -110,6 +110,7 @@
pickerController.pallete = strongController.pallete;
}
pickerController.suggestionContext = strongController.suggestionContext;
pickerController.stickersContext = strongController.stickersContext;
pickerController.localMediaCacheEnabled = strongController.localMediaCacheEnabled;
pickerController.captionsEnabled = strongController.captionsEnabled;
pickerController.allowCaptionEntities = strongController.allowCaptionEntities;
@ -149,6 +150,12 @@
self.pickerController.suggestionContext = suggestionContext;
}
- (void)setStickersContext:(id<TGPhotoPaintStickersContext>)stickersContext
{
_stickersContext = stickersContext;
self.pickerController.stickersContext = stickersContext;
}
- (void)setCaptionsEnabled:(bool)captionsEnabled
{
_captionsEnabled = captionsEnabled;
@ -875,7 +882,11 @@
if ([adjustments cropAppliedForAvatar:false] || adjustments.hasPainting)
{
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);
return TGPhotoEditorCrop(image, adjustments.paintingData.image, adjustments.cropOrientation, 0, scaledCropRect, adjustments.cropMirrored, targetSize, sourceSize, resize);
UIImage *paintingImage = adjustments.paintingData.stillImage;
if (paintingImage == nil) {
paintingImage = adjustments.paintingData.image;
}
return TGPhotoEditorCrop(image, paintingImage, adjustments.cropOrientation, 0, scaledCropRect, adjustments.cropMirrored, targetSize, sourceSize, resize);
}
return image;

View File

@ -323,7 +323,7 @@
- (TGMediaPickerModernGalleryMixin *)_galleryMixinForContext:(id<LegacyComponentsContext>)context item:(id)item thumbnailImage:(UIImage *)thumbnailImage selectionContext:(TGMediaSelectionContext *)selectionContext editingContext:(TGMediaEditingContext *)editingContext suggestionContext:(TGSuggestionContext *)suggestionContext hasCaptions:(bool)hasCaptions allowCaptionEntities:(bool)allowCaptionEntities inhibitDocumentCaptions:(bool)inhibitDocumentCaptions asFile:(bool)asFile
{
return [[TGMediaPickerModernGalleryMixin alloc] initWithContext:context item:item fetchResult:_fetchResult parentController:self thumbnailImage:thumbnailImage selectionContext:selectionContext editingContext:editingContext suggestionContext:suggestionContext hasCaptions:hasCaptions allowCaptionEntities:allowCaptionEntities hasTimer:self.hasTimer onlyCrop:self.onlyCrop inhibitDocumentCaptions:inhibitDocumentCaptions inhibitMute:self.inhibitMute asFile:asFile itemsLimit:0 recipientName:self.recipientName hasSilentPosting:self.hasSilentPosting hasSchedule:self.hasSchedule reminder:self.reminder];
return [[TGMediaPickerModernGalleryMixin alloc] initWithContext:context item:item fetchResult:_fetchResult parentController:self thumbnailImage:thumbnailImage selectionContext:selectionContext editingContext:editingContext suggestionContext:suggestionContext hasCaptions:hasCaptions allowCaptionEntities:allowCaptionEntities hasTimer:self.hasTimer onlyCrop:self.onlyCrop inhibitDocumentCaptions:inhibitDocumentCaptions inhibitMute:self.inhibitMute asFile:asFile itemsLimit:0 recipientName:self.recipientName hasSilentPosting:self.hasSilentPosting hasSchedule:self.hasSchedule reminder:self.reminder stickersContext:self.stickersContext];
}
- (TGMediaPickerModernGalleryMixin *)galleryMixinForIndexPath:(NSIndexPath *)indexPath previewMode:(bool)previewMode outAsset:(TGMediaAsset **)outAsset

View File

@ -78,6 +78,7 @@
TGMemoryImageCache *_thumbnailImageCache;
TGMemoryImageCache *_paintingImageCache;
TGMemoryImageCache *_stillPaintingImageCache;
TGMemoryImageCache *_originalImageCache;
TGMemoryImageCache *_originalThumbnailImageCache;
@ -86,6 +87,7 @@
NSURL *_fullSizeResultsUrl;
NSURL *_paintingDatasUrl;
NSURL *_paintingImagesUrl;
NSURL *_stillPaintingImagesUrl;
NSURL *_videoPaintingImagesUrl;
NSMutableArray *_storeVideoPaintingImages;
@ -131,6 +133,9 @@
_paintingImageCache = [[TGMemoryImageCache alloc] initWithSoftMemoryLimit:[[self class] imageSoftMemoryLimit]
hardMemoryLimit:[[self class] imageHardMemoryLimit]];
_stillPaintingImageCache = [[TGMemoryImageCache alloc] initWithSoftMemoryLimit:[[self class] imageSoftMemoryLimit]
hardMemoryLimit:[[self class] imageHardMemoryLimit]];
_originalImageCache = [[TGMemoryImageCache alloc] initWithSoftMemoryLimit:[[self class] originalImageSoftMemoryLimit]
hardMemoryLimit:[[self class] originalImageHardMemoryLimit]];
_originalThumbnailImageCache = [[TGMemoryImageCache alloc] initWithSoftMemoryLimit:[[self class] thumbnailImageSoftMemoryLimit]
@ -145,6 +150,9 @@
_paintingImagesUrl = [NSURL fileURLWithPath:[[[LegacyComponentsGlobals provider] dataStoragePath] stringByAppendingPathComponent:[NSString stringWithFormat:@"paintingimages/%@", _contextId]]];
[[NSFileManager defaultManager] createDirectoryAtPath:_paintingImagesUrl.path withIntermediateDirectories:true attributes:nil error:nil];
_stillPaintingImagesUrl = [NSURL fileURLWithPath:[[[LegacyComponentsGlobals provider] dataStoragePath] stringByAppendingPathComponent:@"stillpaintingimages"]];
[[NSFileManager defaultManager] createDirectoryAtPath:_stillPaintingImagesUrl.path withIntermediateDirectories:true attributes:nil error:nil];
_videoPaintingImagesUrl = [NSURL fileURLWithPath:[[[LegacyComponentsGlobals provider] dataStoragePath] stringByAppendingPathComponent:@"videopaintingimages"]];
[[NSFileManager defaultManager] createDirectoryAtPath:_videoPaintingImagesUrl.path withIntermediateDirectories:true attributes:nil error:nil];
@ -340,6 +348,27 @@
return result;
}
- (UIImage *)stillPaintingImageForItem:(NSObject<TGMediaEditableItem> *)item
{
NSString *itemId = [self _contextualIdForItemId:item.uniqueIdentifier];
if (itemId == nil)
return nil;
UIImage *result = [_stillPaintingImageCache imageForKey:itemId attributes:NULL];
if (result == nil)
{
NSURL *imageUrl = [_stillPaintingImagesUrl URLByAppendingPathComponent:[NSString stringWithFormat:@"%@.png", [TGStringUtils md5:itemId]]];
UIImage *diskImage = [UIImage imageWithContentsOfFile:imageUrl.path];
if (diskImage != nil)
{
result = diskImage;
[_stillPaintingImageCache setImage:result forKey:itemId attributes:NULL];
}
}
return result;
}
#pragma mark - Caption
- (NSString *)captionForItem:(id<TGMediaEditableItem>)item
@ -602,7 +631,7 @@
[_queue dispatch:block];
}
- (bool)setPaintingData:(NSData *)data image:(UIImage *)image forItem:(NSObject<TGMediaEditableItem> *)item dataUrl:(NSURL **)dataOutUrl imageUrl:(NSURL **)imageOutUrl forVideo:(bool)video
- (bool)setPaintingData:(NSData *)data image:(UIImage *)image stillImage:(UIImage *)stillImage forItem:(NSObject<TGMediaEditableItem> *)item dataUrl:(NSURL **)dataOutUrl imageUrl:(NSURL **)imageOutUrl forVideo:(bool)video
{
NSString *itemId = [self _contextualIdForItemId:item.uniqueIdentifier];
@ -628,6 +657,17 @@
if (video)
[_storeVideoPaintingImages addObject:imageUrl];
if (stillImage != nil) {
NSURL *stillImageUrl = [_stillPaintingImagesUrl URLByAppendingPathComponent:[NSString stringWithFormat:@"%@.png", [TGStringUtils md5:itemId]]];
[_stillPaintingImageCache setImage:stillImage forKey:itemId attributes:NULL];
NSData *stillImageData = UIImagePNGRepresentation(stillImage);
[stillImageData writeToURL:stillImageUrl options:NSDataWritingAtomic error:nil];
if (video)
[_storeVideoPaintingImages addObject:stillImageUrl];
}
return (image == nil || imageSuccess) && (data == nil || dataSuccess);
}

View File

@ -164,7 +164,7 @@
if (recipientName.length > 0)
{
_arrowView = [[UIImageView alloc] initWithImage:TGComponentsImageNamed(@"PhotoPickerArrow")];
_arrowView = [[UIImageView alloc] initWithImage: TGTintedImage([UIImage imageNamed:@"Editor/Recipient"], UIColor.whiteColor)];
_arrowView.alpha = 0.45f;
[_wrapperView addSubview:_arrowView];

View File

@ -387,6 +387,7 @@
TGPhotoEditorControllerIntent intent = isVideo ? TGPhotoEditorControllerVideoIntent : TGPhotoEditorControllerGenericIntent;
TGPhotoEditorController *controller = [[TGPhotoEditorController alloc] initWithContext:_context item:item.editableMediaItem intent:intent adjustments:editorValues caption:caption screenImage:screenImage availableTabs:_interfaceView.currentTabs selectedTab:tab];
controller.editingContext = _editingContext;
controller.stickersContext = _stickersContext;
self.editorController = controller;
controller.suggestionContext = self.suggestionContext;
controller.willFinishEditing = ^(id<TGMediaEditAdjustments> adjustments, id temporaryRep, bool hasChanges)

View File

@ -166,7 +166,8 @@
_actionButton.highlightImage = highlightImage;
_progressView = [[TGMessageImageViewOverlayView alloc] initWithFrame:CGRectMake(0, 0, 50, 50)];
_progressView = [[TGMessageImageViewOverlayView alloc] initWithFrame:CGRectMake(0, 0, 60, 60)];
[_progressView setRadius:60.0];
_progressView.userInteractionEnabled = false;
[_progressView setPlay];
[_actionButton addSubview:_progressView];
@ -864,7 +865,8 @@
if (progressVisible && _progressView == nil)
{
_progressView = [[TGMessageImageViewOverlayView alloc] initWithFrame:CGRectMake(0.0f, 0.0f, 50.0f, 50.0f)];
_progressView = [[TGMessageImageViewOverlayView alloc] initWithFrame:CGRectMake(0.0f, 0.0f, 60.0f, 60.0f)];
[_progressView setRadius:60.0];
_progressView.userInteractionEnabled = false;
_progressView.frame = (CGRect){{CGFloor((self.frame.size.width - _progressView.frame.size.width) / 2.0f), CGFloor((self.frame.size.height - _progressView.frame.size.height) / 2.0f)}, _progressView.frame.size};

View File

@ -41,17 +41,17 @@
@implementation TGMediaPickerModernGalleryMixin
- (instancetype)initWithContext:(id<LegacyComponentsContext>)context item:(id)item fetchResult:(TGMediaAssetFetchResult *)fetchResult parentController:(TGViewController *)parentController thumbnailImage:(UIImage *)thumbnailImage selectionContext:(TGMediaSelectionContext *)selectionContext editingContext:(TGMediaEditingContext *)editingContext suggestionContext:(TGSuggestionContext *)suggestionContext hasCaptions:(bool)hasCaptions allowCaptionEntities:(bool)allowCaptionEntities hasTimer:(bool)hasTimer onlyCrop:(bool)onlyCrop inhibitDocumentCaptions:(bool)inhibitDocumentCaptions inhibitMute:(bool)inhibitMute asFile:(bool)asFile itemsLimit:(NSUInteger)itemsLimit recipientName:(NSString *)recipientName hasSilentPosting:(bool)hasSilentPosting hasSchedule:(bool)hasSchedule reminder:(bool)reminder
- (instancetype)initWithContext:(id<LegacyComponentsContext>)context item:(id)item fetchResult:(TGMediaAssetFetchResult *)fetchResult parentController:(TGViewController *)parentController thumbnailImage:(UIImage *)thumbnailImage selectionContext:(TGMediaSelectionContext *)selectionContext editingContext:(TGMediaEditingContext *)editingContext suggestionContext:(TGSuggestionContext *)suggestionContext hasCaptions:(bool)hasCaptions allowCaptionEntities:(bool)allowCaptionEntities hasTimer:(bool)hasTimer onlyCrop:(bool)onlyCrop inhibitDocumentCaptions:(bool)inhibitDocumentCaptions inhibitMute:(bool)inhibitMute asFile:(bool)asFile itemsLimit:(NSUInteger)itemsLimit recipientName:(NSString *)recipientName hasSilentPosting:(bool)hasSilentPosting hasSchedule:(bool)hasSchedule reminder:(bool)reminder stickersContext:(id<TGPhotoPaintStickersContext>)stickersContext
{
return [self initWithContext:context item:item fetchResult:fetchResult momentList:nil parentController:parentController thumbnailImage:thumbnailImage selectionContext:selectionContext editingContext:editingContext suggestionContext:suggestionContext hasCaptions:hasCaptions allowCaptionEntities:allowCaptionEntities hasTimer:hasTimer onlyCrop:onlyCrop inhibitDocumentCaptions:inhibitDocumentCaptions inhibitMute:inhibitMute asFile:asFile itemsLimit:itemsLimit recipientName:recipientName hasSilentPosting:hasSilentPosting hasSchedule:hasSchedule reminder:reminder];
return [self initWithContext:context item:item fetchResult:fetchResult momentList:nil parentController:parentController thumbnailImage:thumbnailImage selectionContext:selectionContext editingContext:editingContext suggestionContext:suggestionContext hasCaptions:hasCaptions allowCaptionEntities:allowCaptionEntities hasTimer:hasTimer onlyCrop:onlyCrop inhibitDocumentCaptions:inhibitDocumentCaptions inhibitMute:inhibitMute asFile:asFile itemsLimit:itemsLimit recipientName:recipientName hasSilentPosting:hasSilentPosting hasSchedule:hasSchedule reminder:reminder stickersContext:stickersContext];
}
- (instancetype)initWithContext:(id<LegacyComponentsContext>)context item:(id)item momentList:(TGMediaAssetMomentList *)momentList parentController:(TGViewController *)parentController thumbnailImage:(UIImage *)thumbnailImage selectionContext:(TGMediaSelectionContext *)selectionContext editingContext:(TGMediaEditingContext *)editingContext suggestionContext:(TGSuggestionContext *)suggestionContext hasCaptions:(bool)hasCaptions allowCaptionEntities:(bool)allowCaptionEntities hasTimer:(bool)hasTimer onlyCrop:(bool)onlyCrop inhibitDocumentCaptions:(bool)inhibitDocumentCaptions inhibitMute:(bool)inhibitMute asFile:(bool)asFile itemsLimit:(NSUInteger)itemsLimit hasSilentPosting:(bool)hasSilentPosting hasSchedule:(bool)hasSchedule reminder:(bool)reminder
- (instancetype)initWithContext:(id<LegacyComponentsContext>)context item:(id)item momentList:(TGMediaAssetMomentList *)momentList parentController:(TGViewController *)parentController thumbnailImage:(UIImage *)thumbnailImage selectionContext:(TGMediaSelectionContext *)selectionContext editingContext:(TGMediaEditingContext *)editingContext suggestionContext:(TGSuggestionContext *)suggestionContext hasCaptions:(bool)hasCaptions allowCaptionEntities:(bool)allowCaptionEntities hasTimer:(bool)hasTimer onlyCrop:(bool)onlyCrop inhibitDocumentCaptions:(bool)inhibitDocumentCaptions inhibitMute:(bool)inhibitMute asFile:(bool)asFile itemsLimit:(NSUInteger)itemsLimit hasSilentPosting:(bool)hasSilentPosting hasSchedule:(bool)hasSchedule reminder:(bool)reminder stickersContext:(id<TGPhotoPaintStickersContext>)stickersContext
{
return [self initWithContext:context item:item fetchResult:nil momentList:momentList parentController:parentController thumbnailImage:thumbnailImage selectionContext:selectionContext editingContext:editingContext suggestionContext:suggestionContext hasCaptions:hasCaptions allowCaptionEntities:allowCaptionEntities hasTimer:hasTimer onlyCrop:onlyCrop inhibitDocumentCaptions:inhibitDocumentCaptions inhibitMute:inhibitMute asFile:asFile itemsLimit:itemsLimit recipientName:nil hasSilentPosting:hasSilentPosting hasSchedule:hasSchedule reminder:reminder];
return [self initWithContext:context item:item fetchResult:nil momentList:momentList parentController:parentController thumbnailImage:thumbnailImage selectionContext:selectionContext editingContext:editingContext suggestionContext:suggestionContext hasCaptions:hasCaptions allowCaptionEntities:allowCaptionEntities hasTimer:hasTimer onlyCrop:onlyCrop inhibitDocumentCaptions:inhibitDocumentCaptions inhibitMute:inhibitMute asFile:asFile itemsLimit:itemsLimit recipientName:nil hasSilentPosting:hasSilentPosting hasSchedule:hasSchedule reminder:reminder stickersContext:stickersContext];
}
- (instancetype)initWithContext:(id<LegacyComponentsContext>)context item:(id)item fetchResult:(TGMediaAssetFetchResult *)fetchResult momentList:(TGMediaAssetMomentList *)momentList parentController:(TGViewController *)parentController thumbnailImage:(UIImage *)thumbnailImage selectionContext:(TGMediaSelectionContext *)selectionContext editingContext:(TGMediaEditingContext *)editingContext suggestionContext:(TGSuggestionContext *)suggestionContext hasCaptions:(bool)hasCaptions allowCaptionEntities:(bool)allowCaptionEntities hasTimer:(bool)hasTimer onlyCrop:(bool)onlyCrop inhibitDocumentCaptions:(bool)inhibitDocumentCaptions inhibitMute:(bool)inhibitMute asFile:(bool)asFile itemsLimit:(NSUInteger)itemsLimit recipientName:(NSString *)recipientName hasSilentPosting:(bool)hasSilentPosting hasSchedule:(bool)hasSchedule reminder:(bool)reminder
- (instancetype)initWithContext:(id<LegacyComponentsContext>)context item:(id)item fetchResult:(TGMediaAssetFetchResult *)fetchResult momentList:(TGMediaAssetMomentList *)momentList parentController:(TGViewController *)parentController thumbnailImage:(UIImage *)thumbnailImage selectionContext:(TGMediaSelectionContext *)selectionContext editingContext:(TGMediaEditingContext *)editingContext suggestionContext:(TGSuggestionContext *)suggestionContext hasCaptions:(bool)hasCaptions allowCaptionEntities:(bool)allowCaptionEntities hasTimer:(bool)hasTimer onlyCrop:(bool)onlyCrop inhibitDocumentCaptions:(bool)inhibitDocumentCaptions inhibitMute:(bool)inhibitMute asFile:(bool)asFile itemsLimit:(NSUInteger)itemsLimit recipientName:(NSString *)recipientName hasSilentPosting:(bool)hasSilentPosting hasSchedule:(bool)hasSchedule reminder:(bool)reminder stickersContext:(id<TGPhotoPaintStickersContext>)stickersContext
{
self = [super init];
if (self != nil)
@ -85,6 +85,7 @@
TGMediaPickerGalleryModel *model = [[TGMediaPickerGalleryModel alloc] initWithContext:[_windowManager context] items:galleryItems focusItem:focusItem selectionContext:selectionContext editingContext:editingContext hasCaptions:hasCaptions allowCaptionEntities:allowCaptionEntities hasTimer:hasTimer onlyCrop:onlyCrop inhibitDocumentCaptions:inhibitDocumentCaptions hasSelectionPanel:true hasCamera:false recipientName:recipientName];
_galleryModel = model;
model.stickersContext = stickersContext;
model.inhibitMute = inhibitMute;
model.controller = modernGallery;
model.suggestionContext = suggestionContext;

View File

@ -3,13 +3,18 @@
#import <CommonCrypto/CommonDigest.h>
#import <sys/stat.h>
#import "GPUImageContext.h"
#import "LegacyComponentsInternal.h"
#import "TGImageUtils.h"
#import "TGPhotoEditorUtils.h"
#import "PGPhotoEditor.h"
#import "TGPhotoPaintEntity.h"
#import "TGVideoEditAdjustments.h"
#import "TGPaintingData.h"
#import "TGPhotoPaintStickersContext.h"
@interface TGMediaVideoConversionPresetSettings ()
@ -68,6 +73,8 @@
@property (nonatomic, readonly) TGMediaSampleBufferProcessor *videoProcessor;
@property (nonatomic, readonly) TGMediaSampleBufferProcessor *audioProcessor;
@property (nonatomic, readonly) id<TGPhotoPaintEntityRenderer> entityRenderer;
@property (nonatomic, readonly) CMTimeRange timeRange;
@property (nonatomic, readonly) CGSize dimensions;
@property (nonatomic, readonly) UIImage *coverImage;
@ -79,7 +86,7 @@
- (instancetype)addImageGenerator:(AVAssetImageGenerator *)imageGenerator;
- (instancetype)addCoverImage:(UIImage *)coverImage;
- (instancetype)contextWithAssetReader:(AVAssetReader *)assetReader assetWriter:(AVAssetWriter *)assetWriter videoProcessor:(TGMediaSampleBufferProcessor *)videoProcessor audioProcessor:(TGMediaSampleBufferProcessor *)audioProcessor timeRange:(CMTimeRange)timeRange dimensions:(CGSize)dimensions;
- (instancetype)contextWithAssetReader:(AVAssetReader *)assetReader assetWriter:(AVAssetWriter *)assetWriter videoProcessor:(TGMediaSampleBufferProcessor *)videoProcessor audioProcessor:(TGMediaSampleBufferProcessor *)audioProcessor timeRange:(CMTimeRange)timeRange dimensions:(CGSize)dimensions entityRenderer:(id<TGPhotoPaintEntityRenderer>)entityRenderer;
@end
@ -93,12 +100,12 @@
@implementation TGMediaVideoConverter
+ (SSignal *)convertAVAsset:(AVAsset *)avAsset adjustments:(TGMediaVideoEditAdjustments *)adjustments watcher:(TGMediaVideoFileWatcher *)watcher
+ (SSignal *)convertAVAsset:(AVAsset *)avAsset adjustments:(TGMediaVideoEditAdjustments *)adjustments watcher:(TGMediaVideoFileWatcher *)watcher entityRenderer:(id<TGPhotoPaintEntityRenderer>)entityRenderer
{
return [self convertAVAsset:avAsset adjustments:adjustments watcher:watcher inhibitAudio:false];
return [self convertAVAsset:avAsset adjustments:adjustments watcher:watcher inhibitAudio:false entityRenderer:entityRenderer];
}
+ (SSignal *)convertAVAsset:(AVAsset *)avAsset adjustments:(TGMediaVideoEditAdjustments *)adjustments watcher:(TGMediaVideoFileWatcher *)watcher inhibitAudio:(bool)inhibitAudio
+ (SSignal *)convertAVAsset:(AVAsset *)avAsset adjustments:(TGMediaVideoEditAdjustments *)adjustments watcher:(TGMediaVideoFileWatcher *)watcher inhibitAudio:(bool)inhibitAudio entityRenderer:(id<TGPhotoPaintEntityRenderer>)entityRenderer
{
SQueue *queue = [[SQueue alloc] init];
@ -146,7 +153,7 @@
}
}
if (![self setupAssetReaderWriterForAVAsset:avAsset outputURL:outputUrl preset:preset adjustments:adjustments inhibitAudio:inhibitAudio conversionContext:context error:&error])
if (![self setupAssetReaderWriterForItem:avAsset outputURL:outputUrl preset:preset entityRenderer:entityRenderer adjustments:adjustments inhibitAudio:inhibitAudio conversionContext:context error:&error])
{
[subscriber putError:error];
return;
@ -204,6 +211,92 @@
}];
}
+ (SSignal *)renderUIImage:(UIImage *)image adjustments:(TGMediaVideoEditAdjustments *)adjustments watcher:(TGMediaVideoFileWatcher *)watcher entityRenderer:(id<TGPhotoPaintEntityRenderer>)entityRenderer
{
SQueue *queue = [[SQueue alloc] init];
return [[SSignal alloc] initWithGenerator:^id<SDisposable>(SSubscriber *subscriber)
{
SAtomic *context = [[SAtomic alloc] initWithValue:[TGMediaVideoConversionContext contextWithQueue:queue subscriber:subscriber]];
NSURL *outputUrl = [self _randomTemporaryURL];
[queue dispatch:^
{
if (((TGMediaVideoConversionContext *)context.value).cancelled)
return;
TGMediaVideoConversionPreset preset = TGMediaVideoConversionPresetAnimation;
NSError *error = nil;
NSString *outputPath = outputUrl.path;
NSFileManager *fileManager = [NSFileManager defaultManager];
if ([fileManager fileExistsAtPath:outputPath])
{
[fileManager removeItemAtPath:outputPath error:&error];
if (error != nil)
{
[subscriber putError:error];
return;
}
}
if (![self setupAssetReaderWriterForItem:image outputURL:outputUrl preset:preset entityRenderer:entityRenderer adjustments:adjustments inhibitAudio:true conversionContext:context error:&error])
{
[subscriber putError:error];
return;
}
TGDispatchAfter(1.0, queue._dispatch_queue, ^
{
if (watcher != nil)
[watcher setupWithFileURL:outputUrl];
});
[self processWithConversionContext:context completionBlock:^
{
TGMediaVideoConversionContext *resultContext = context.value;
[resultContext.imageGenerator generateCGImagesAsynchronouslyForTimes:@[ [NSValue valueWithCMTime:kCMTimeZero] ] completionHandler:^(__unused CMTime requestedTime, CGImageRef _Nullable image, __unused CMTime actualTime, AVAssetImageGeneratorResult result, __unused NSError * _Nullable error)
{
UIImage *coverImage = nil;
if (result == AVAssetImageGeneratorSucceeded)
coverImage = [UIImage imageWithCGImage:image];
__block TGMediaVideoConversionResult *contextResult = nil;
[context modify:^id(TGMediaVideoConversionContext *resultContext)
{
id liveUploadData = nil;
if (watcher != nil)
liveUploadData = [watcher fileUpdated:true];
contextResult = [TGMediaVideoConversionResult resultWithFileURL:outputUrl fileSize:0 duration:CMTimeGetSeconds(resultContext.timeRange.duration) dimensions:resultContext.dimensions coverImage:coverImage liveUploadData:liveUploadData];
return [resultContext finishedContext];
}];
[subscriber putNext:contextResult];
[subscriber putCompletion];
}];
}];
}];
return [[SBlockDisposable alloc] initWithBlock:^
{
[queue dispatch:^
{
[context modify:^id(TGMediaVideoConversionContext *currentContext)
{
if (currentContext.finished)
return currentContext;
[currentContext.videoProcessor cancel];
return [currentContext cancelledContext];
}];
}];
}];
}];
}
+ (CGSize)dimensionsFor:(CGSize)dimensions adjustments:(TGMediaVideoEditAdjustments *)adjustments preset:(TGMediaVideoConversionPreset)preset {
CGRect transformedRect = CGRectMake(0.0f, 0.0f, dimensions.width, dimensions.height);
@ -221,7 +314,7 @@
return outputDimensions;
}
+ (AVAssetReaderVideoCompositionOutput *)setupVideoCompositionOutputWithAVAsset:(AVAsset *)avAsset composition:(AVMutableComposition *)composition videoTrack:(AVAssetTrack *)videoTrack preset:(TGMediaVideoConversionPreset)preset adjustments:(TGMediaVideoEditAdjustments *)adjustments timeRange:(CMTimeRange)timeRange outputSettings:(NSDictionary **)outputSettings dimensions:(CGSize *)dimensions conversionContext:(SAtomic *)conversionContext
+ (AVAssetReaderVideoCompositionOutput *)setupVideoCompositionOutputWithAVAsset:(AVAsset *)avAsset composition:(AVMutableComposition *)composition videoTrack:(AVAssetTrack *)videoTrack preset:(TGMediaVideoConversionPreset)preset entityRenderer:(id<TGPhotoPaintEntityRenderer>)entityRenderer adjustments:(TGMediaVideoEditAdjustments *)adjustments timeRange:(CMTimeRange)timeRange outputSettings:(NSDictionary **)outputSettings dimensions:(CGSize *)dimensions conversionContext:(SAtomic *)conversionContext
{
CGSize transformedSize = CGRectApplyAffineTransform((CGRect){CGPointZero, videoTrack.naturalSize}, videoTrack.preferredTransform).size;;
CGRect transformedRect = CGRectMake(0, 0, transformedSize.width, transformedSize.height);
@ -241,7 +334,80 @@
if (TGOrientationIsSideward(adjustments.cropOrientation, NULL))
outputDimensions = CGSizeMake(outputDimensions.height, outputDimensions.width);
AVMutableVideoComposition *videoComposition = [AVMutableVideoComposition videoComposition];
AVMutableCompositionTrack *trimVideoTrack = [composition addMutableTrackWithMediaType:AVMediaTypeVideo preferredTrackID:kCMPersistentTrackID_Invalid];
[trimVideoTrack insertTimeRange:timeRange ofTrack:videoTrack atTime:kCMTimeZero error:NULL];
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;
CIContext *ciContext = nil;
if (adjustments.toolsApplied) {
editor = [[PGPhotoEditor alloc] initWithOriginalSize:adjustments.originalSize adjustments:adjustments forVideo:true enableStickers:true];
ciContext = [CIContext contextWithEAGLContext:[[GPUImageContext sharedImageProcessingContext] context]];
}
__block CIImage *overlayCIImage = nil;
videoComposition = [AVMutableVideoComposition videoCompositionWithAsset:avAsset applyingCIFiltersWithHandler:^(AVAsynchronousCIImageFilteringRequest * _Nonnull request) {
__block CIImage *resultImage = request.sourceImage;
if (editor != nil) {
[editor setCIImage:resultImage];
resultImage = editor.currentResultCIImage;
}
if (overlayImage != nil && overlayImage.size.width > 0.0) {
if (overlayCIImage == nil) {
overlayCIImage = [[CIImage alloc] initWithImage:overlayImage];
CGFloat scale = request.sourceImage.extent.size.width / overlayCIImage.extent.size.width;
overlayCIImage = [overlayCIImage imageByApplyingTransform:CGAffineTransformMakeScale(scale, scale)];
}
resultImage = [overlayCIImage imageByCompositingOverImage:resultImage];
}
if (entityRenderer != nil) {
[entityRenderer entitiesForTime:request.compositionTime size:request.sourceImage.extent.size completion:^(NSArray<CIImage *> *images) {
for (CIImage *image in images) {
resultImage = [image imageByCompositingOverImage:resultImage];
}
[request finishWithImage:resultImage context:ciContext];
}];
} else {
[request finishWithImage:resultImage context:ciContext];
}
}];
} else {
videoComposition = [AVMutableVideoComposition videoComposition];
bool mirrored = false;
UIImageOrientation videoOrientation = TGVideoOrientationForAsset(avAsset, &mirrored);
CGAffineTransform transform = TGVideoTransformForOrientation(videoOrientation, videoTrack.naturalSize, cropRect, mirrored);
CGAffineTransform rotationTransform = TGVideoTransformForCrop(adjustments.cropOrientation, cropRect.size, adjustments.cropMirrored);
CGAffineTransform finalTransform = CGAffineTransformConcat(transform, rotationTransform);
AVMutableVideoCompositionLayerInstruction *transformer = [AVMutableVideoCompositionLayerInstruction videoCompositionLayerInstructionWithAssetTrack:trimVideoTrack];
[transformer setTransform:finalTransform atTime:kCMTimeZero];
AVMutableVideoCompositionInstruction *instruction = [AVMutableVideoCompositionInstruction videoCompositionInstruction];
instruction.timeRange = CMTimeRangeMake(kCMTimeZero, timeRange.duration);
instruction.layerInstructions = [NSArray arrayWithObject:transformer];
videoComposition.instructions = [NSArray arrayWithObject:instruction];
}
if (videoTrack.nominalFrameRate > 0)
videoComposition.frameDuration = CMTimeMake(1, (int32_t)videoTrack.nominalFrameRate);
else if (CMTimeCompare(videoTrack.minFrameDuration, kCMTimeZero) == 1)
@ -259,28 +425,7 @@
if (videoComposition.renderSize.width < FLT_EPSILON || videoComposition.renderSize.height < FLT_EPSILON)
return nil;
AVMutableCompositionTrack *trimVideoTrack = [composition addMutableTrackWithMediaType:AVMediaTypeVideo preferredTrackID:kCMPersistentTrackID_Invalid];
[trimVideoTrack insertTimeRange:timeRange ofTrack:videoTrack atTime:kCMTimeZero error:NULL];
bool mirrored = false;
UIImageOrientation videoOrientation = TGVideoOrientationForAsset(avAsset, &mirrored);
CGAffineTransform transform = TGVideoTransformForOrientation(videoOrientation, videoTrack.naturalSize, cropRect, mirrored);
CGAffineTransform rotationTransform = TGVideoTransformForCrop(adjustments.cropOrientation, cropRect.size, adjustments.cropMirrored);
CGAffineTransform finalTransform = CGAffineTransformConcat(transform, rotationTransform);
AVMutableVideoCompositionLayerInstruction *transformer = [AVMutableVideoCompositionLayerInstruction videoCompositionLayerInstructionWithAssetTrack:trimVideoTrack];
[transformer setTransform:finalTransform atTime:kCMTimeZero];
AVMutableVideoCompositionInstruction *instruction = [AVMutableVideoCompositionInstruction videoCompositionInstruction];
instruction.timeRange = CMTimeRangeMake(kCMTimeZero, timeRange.duration);
instruction.layerInstructions = [NSArray arrayWithObject:transformer];
videoComposition.instructions = [NSArray arrayWithObject:instruction];
UIImage *overlayImage = nil;
if (adjustments.paintingData.imagePath != nil)
overlayImage = [UIImage imageWithContentsOfFile:adjustments.paintingData.imagePath];
if (overlayImage != nil)
if (overlayImage != nil && entityRenderer == nil)
{
CALayer *parentLayer = [CALayer layer];
parentLayer.frame = CGRectMake(0, 0, videoComposition.renderSize.width, videoComposition.renderSize.height);
@ -335,11 +480,14 @@
return output;
}
+ (bool)setupAssetReaderWriterForAVAsset:(AVAsset *)avAsset outputURL:(NSURL *)outputURL preset:(TGMediaVideoConversionPreset)preset adjustments:(TGMediaVideoEditAdjustments *)adjustments inhibitAudio:(bool)inhibitAudio conversionContext:(SAtomic *)outConversionContext error:(NSError **)error
+ (bool)setupAssetReaderWriterForItem:(id)item outputURL:(NSURL *)outputURL preset:(TGMediaVideoConversionPreset)preset entityRenderer:(id<TGPhotoPaintEntityRenderer>)entityRenderer adjustments:(TGMediaVideoEditAdjustments *)adjustments inhibitAudio:(bool)inhibitAudio conversionContext:(SAtomic *)outConversionContext error:(NSError **)error
{
if ([item isKindOfClass:[AVAsset class]]) {
TGMediaSampleBufferProcessor *videoProcessor = nil;
TGMediaSampleBufferProcessor *audioProcessor = nil;
AVAsset *avAsset = (AVAsset *)item;
AVAssetTrack *audioTrack = [[avAsset tracksWithMediaType:AVMediaTypeAudio] firstObject];
AVAssetTrack *videoTrack = [[avAsset tracksWithMediaType:AVMediaTypeVideo] firstObject];
if (videoTrack == nil)
@ -363,7 +511,7 @@
NSDictionary *outputSettings = nil;
AVMutableComposition *composition = [AVMutableComposition composition];
AVAssetReaderVideoCompositionOutput *output = [self setupVideoCompositionOutputWithAVAsset:avAsset composition:composition videoTrack:videoTrack preset:preset adjustments:adjustments timeRange:timeRange outputSettings:&outputSettings dimensions:&dimensions conversionContext:outConversionContext];
AVAssetReaderVideoCompositionOutput *output = [self setupVideoCompositionOutputWithAVAsset:avAsset composition:composition videoTrack:videoTrack preset:preset entityRenderer:entityRenderer adjustments:adjustments timeRange:timeRange outputSettings:&outputSettings dimensions:&dimensions conversionContext:outConversionContext];
if (output == nil)
return false;
@ -378,14 +526,6 @@
[assetReader addOutput:output];
AVAssetWriterInput *input = [AVAssetWriterInput assetWriterInputWithMediaType:AVMediaTypeVideo outputSettings:outputSettings];
NSDictionary *sourcePixelBufferAttributesDictionary = [NSDictionary dictionaryWithObjectsAndKeys: [NSNumber numberWithInt:kCVPixelFormatType_32BGRA], kCVPixelBufferPixelFormatTypeKey,
[NSNumber numberWithInt:dimensions.width], kCVPixelBufferWidthKey,
[NSNumber numberWithInt:dimensions.height], kCVPixelBufferHeightKey,
nil];
AVAssetWriterInputPixelBufferAdaptor *pixelBufferInput = [AVAssetWriterInputPixelBufferAdaptor assetWriterInputPixelBufferAdaptorWithAssetWriterInput:input sourcePixelBufferAttributes:sourcePixelBufferAttributesDictionary];
[assetWriter addInput:input];
videoProcessor = [[TGMediaSampleBufferProcessor alloc] initWithAssetReaderOutput:output assetWriterInput:input];
@ -408,10 +548,45 @@
[outConversionContext modify:^id(TGMediaVideoConversionContext *currentContext)
{
return [currentContext contextWithAssetReader:assetReader assetWriter:assetWriter videoProcessor:videoProcessor audioProcessor:audioProcessor timeRange:timeRange dimensions:dimensions];
return [currentContext contextWithAssetReader:assetReader assetWriter:assetWriter videoProcessor:videoProcessor audioProcessor:audioProcessor timeRange:timeRange dimensions:dimensions entityRenderer:entityRenderer];
}];
return true;
} else if ([item isKindOfClass:[UIImage class]]) {
TGMediaSampleBufferProcessor *videoProcessor = nil;
CGSize dimensions = CGSizeZero;
NSDictionary *outputSettings = nil;
CMTimeRange timeRange = CMTimeRangeMake(CMTimeMakeWithSeconds(0.0, NSEC_PER_SEC), CMTimeMakeWithSeconds(4.0, NSEC_PER_SEC));
AVMutableComposition *composition = [AVMutableComposition composition];
AVAssetTrack *videoTrack = [composition addMutableTrackWithMediaType:AVMediaTypeVideo preferredTrackID:kCMPersistentTrackID_Invalid];
AVAssetReaderVideoCompositionOutput *output = [self setupVideoCompositionOutputWithAVAsset:composition composition:composition videoTrack:videoTrack preset:preset entityRenderer:entityRenderer adjustments:adjustments timeRange:timeRange outputSettings:&outputSettings dimensions:&dimensions conversionContext:outConversionContext];
if (output == nil)
return false;
AVAssetReader *assetReader = [[AVAssetReader alloc] initWithAsset:composition error:error];
if (assetReader == nil)
return false;
AVAssetWriter *assetWriter = [[AVAssetWriter alloc] initWithURL:outputURL fileType:AVFileTypeMPEG4 error:error];
if (assetWriter == nil)
return false;
[assetReader addOutput:output];
AVAssetWriterInput *input = [AVAssetWriterInput assetWriterInputWithMediaType:AVMediaTypeVideo outputSettings:outputSettings];
[assetWriter addInput:input];
videoProcessor = [[TGMediaSampleBufferProcessor alloc] initWithAssetReaderOutput:output assetWriterInput:input];
[outConversionContext modify:^id(TGMediaVideoConversionContext *currentContext)
{
return [currentContext contextWithAssetReader:assetReader assetWriter:assetWriter videoProcessor:videoProcessor audioProcessor:nil timeRange:timeRange dimensions:dimensions entityRenderer:entityRenderer];
}];
return true;
}
return false;
}
+ (void)processWithConversionContext:(SAtomic *)context_ completionBlock:(void (^)(void))completionBlock
@ -865,6 +1040,7 @@ static CGFloat progressOfSampleBufferInTimeRange(CMSampleBufferRef sampleBuffer,
context->_dimensions = _dimensions;
context->_coverImage = _coverImage;
context->_imageGenerator = _imageGenerator;
context->_entityRenderer = _entityRenderer;
return context;
}
@ -883,6 +1059,7 @@ static CGFloat progressOfSampleBufferInTimeRange(CMSampleBufferRef sampleBuffer,
context->_dimensions = _dimensions;
context->_coverImage = _coverImage;
context->_imageGenerator = _imageGenerator;
context->_entityRenderer = _entityRenderer;
return context;
}
@ -900,6 +1077,7 @@ static CGFloat progressOfSampleBufferInTimeRange(CMSampleBufferRef sampleBuffer,
context->_dimensions = _dimensions;
context->_coverImage = _coverImage;
context->_imageGenerator = imageGenerator;
context->_entityRenderer = _entityRenderer;
return context;
}
@ -917,10 +1095,11 @@ static CGFloat progressOfSampleBufferInTimeRange(CMSampleBufferRef sampleBuffer,
context->_dimensions = _dimensions;
context->_coverImage = coverImage;
context->_imageGenerator = _imageGenerator;
context->_entityRenderer = _entityRenderer;
return context;
}
- (instancetype)contextWithAssetReader:(AVAssetReader *)assetReader assetWriter:(AVAssetWriter *)assetWriter videoProcessor:(TGMediaSampleBufferProcessor *)videoProcessor audioProcessor:(TGMediaSampleBufferProcessor *)audioProcessor timeRange:(CMTimeRange)timeRange dimensions:(CGSize)dimensions
- (instancetype)contextWithAssetReader:(AVAssetReader *)assetReader assetWriter:(AVAssetWriter *)assetWriter videoProcessor:(TGMediaSampleBufferProcessor *)videoProcessor audioProcessor:(TGMediaSampleBufferProcessor *)audioProcessor timeRange:(CMTimeRange)timeRange dimensions:(CGSize)dimensions entityRenderer:(id<TGPhotoPaintEntityRenderer>)entityRenderer
{
TGMediaVideoConversionContext *context = [[TGMediaVideoConversionContext alloc] init];
context->_queue = _queue;
@ -934,6 +1113,7 @@ static CGFloat progressOfSampleBufferInTimeRange(CMSampleBufferRef sampleBuffer,
context->_dimensions = dimensions;
context->_coverImage = _coverImage;
context->_imageGenerator = _imageGenerator;
context->_entityRenderer = entityRenderer;
return context;
}

View File

@ -702,7 +702,7 @@ const NSInteger TGMessageImageViewOverlayParticlesCount = 40;
CGFloat offset = round(diameter * 0.06f);
CGFloat verticalOffset = 0.0f;
CGFloat alpha = 0.8f;
UIColor *iconColor = TGColorWithHexAndAlpha(0xff000000, 0.45f);
UIColor *iconColor = TGColorWithHexAndAlpha(0xffffffff, 1.0f);
if (diameter <= 25.0f + FLT_EPSILON) {
offset = round(50.0f * 0.06f) - 1.0f;
verticalOffset += 0.5f;
@ -730,16 +730,11 @@ const NSInteger TGMessageImageViewOverlayParticlesCount = 40;
}
else
{
CGContextSetFillColorWithColor(context, TGColorWithHexAndAlpha(0xffffffff, alpha).CGColor);
CGContextSetFillColorWithColor(context, TGColorWithHexAndAlpha(0x00000000, 0.3).CGColor);
CGContextFillEllipseInRect(context, CGRectMake(0.0f, 0.0f, diameter, diameter));
CGContextBeginPath(context);
CGContextMoveToPoint(context, offset + floor((diameter - width) / 2.0f), verticalOffset + floor((diameter - height) / 2.0f));
CGContextAddLineToPoint(context, offset + floor((diameter - width) / 2.0f) + width, verticalOffset + floor(diameter / 2.0f));
CGContextAddLineToPoint(context, offset + floor((diameter - width) / 2.0f), verticalOffset + floor((diameter + height) / 2.0f));
CGContextClosePath(context);
CGContextSetFillColorWithColor(context, iconColor.CGColor);
CGContextFillPath(context);
UIImage *iconImage = TGTintedImage([UIImage imageNamed:@"Editor/Play"], iconColor);
[iconImage drawAtPoint:CGPointMake(floor((diameter - iconImage.size.width) / 2.0f), floor((diameter - iconImage.size.height) / 2.0f)) blendMode:kCGBlendModeNormal alpha:1.0f];
}
break;

View File

@ -24,7 +24,7 @@
_containerView = [[TGModernGalleryImageItemContainerView alloc] initWithFrame:_internalContainerView.bounds];
[_internalContainerView addSubview:_containerView];
_scrollView = [[TGModernGalleryZoomableScrollView alloc] initWithFrame:_containerView.bounds];
_scrollView = [[TGModernGalleryZoomableScrollView alloc] initWithFrame:_containerView.bounds hasDoubleTap:true];
_scrollView.delegate = self;
_scrollView.showsHorizontalScrollIndicator = false;
_scrollView.showsVerticalScrollIndicator = false;

View File

@ -3,25 +3,48 @@
#import "TGDoubleTapGestureRecognizer.h"
@interface TGModernGalleryZoomableScrollView () <TGDoubleTapGestureRecognizerDelegate>
{
bool _hasDoubleTap;
}
@end
@implementation TGModernGalleryZoomableScrollView
- (instancetype)initWithFrame:(CGRect)frame
- (instancetype)initWithFrame:(CGRect)frame hasDoubleTap:(bool)hasDoubleTap
{
self = [super initWithFrame:frame];
if (self != nil)
{
_hasDoubleTap = hasDoubleTap;
if (hasDoubleTap) {
TGDoubleTapGestureRecognizer *recognizer = [[TGDoubleTapGestureRecognizer alloc] initWithTarget:self action:@selector(doubleTapGesture:)];
recognizer.consumeSingleTap = true;
[self addGestureRecognizer:recognizer];
} else {
self.panGestureRecognizer.minimumNumberOfTouches = 2;
}
_normalZoomScale = 1.0f;
}
return self;
}
- (void)setContentInset:(UIEdgeInsets)contentInset {
if (_hasDoubleTap) {
[super setContentInset:contentInset];
} else {
[super setContentInset:UIEdgeInsetsZero];
}
}
- (UIEdgeInsets)adjustedContentInset {
if (_hasDoubleTap) {
return [super adjustedContentInset];
} else {
return UIEdgeInsetsZero;
}
}
- (void)doubleTapGesture:(TGDoubleTapGestureRecognizer *)recognizer
{
if (recognizer.state == UIGestureRecognizerStateRecognized)

View File

@ -2,7 +2,7 @@
#import <LegacyComponents/LegacyComponents.h>
const CGSize TGPaintBrushTextureSize = { 256.0f, 256.0f };
const CGSize TGPaintBrushTextureSize = { 384.0f, 384.0f };
const CGSize TGPaintBrushPreviewTextureSize = { 64.0f, 64.0f };
@interface TGPaintBrush ()

View File

@ -22,6 +22,8 @@
CGAffineTransform _canvasTransform;
CGRect _dirtyRect;
CGRect _visibleRect;
TGPaintInput *_input;
TGPaintPanGestureRecognizer *_gestureRecognizer;
bool _beganDrawing;
@ -40,6 +42,8 @@
if (self != nil)
{
self.contentScaleFactor = _screenScale;
self.multipleTouchEnabled = true;
self.exclusiveTouch = true;
_state = [[TGPaintState alloc] init];
@ -82,10 +86,18 @@
- (void)setFrame:(CGRect)frame
{
[super setFrame:frame];
_visibleRect = self.bounds;
[self _updateTransform];
}
- (void)setBounds:(CGRect)bounds
{
[super setBounds:bounds];
_visibleRect = bounds;
}
- (void)_updateTransform
{
CGAffineTransform transform = CGAffineTransformIdentity;
@ -112,7 +124,7 @@
_gestureRecognizer = [[TGPaintPanGestureRecognizer alloc] initWithTarget:self action:@selector(handlePan:)];
_gestureRecognizer.delegate = self;
_gestureRecognizer.minimumNumberOfTouches = 1;
_gestureRecognizer.maximumNumberOfTouches = 1;
_gestureRecognizer.maximumNumberOfTouches = 2;
__weak TGPaintCanvas *weakSelf = self;
_gestureRecognizer.shouldRecognizeTap = ^bool
@ -162,7 +174,7 @@
}
}
- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)__unused gestureRecognizer
- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer
{
if (self.shouldDraw != nil)
return self.shouldDraw();
@ -172,9 +184,9 @@
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer
{
if (gestureRecognizer == _gestureRecognizer && ([otherGestureRecognizer isKindOfClass:[UIPinchGestureRecognizer class]] || [otherGestureRecognizer isKindOfClass:[UIRotationGestureRecognizer class]]))
return false;
// if (gestureRecognizer == _gestureRecognizer && ([otherGestureRecognizer isKindOfClass:[UIPinchGestureRecognizer class]] || [otherGestureRecognizer isKindOfClass:[UIRotationGestureRecognizer class]]))
// return false;
//
return true;
}
@ -264,16 +276,18 @@
- (CGRect)visibleRect
{
return self.bounds;
return _visibleRect;
}
- (void)layoutSubviews
{
[super layoutSubviews];
[self.painting performSynchronouslyInContext:^{
[_buffers update];
[self draw];
}];
}
#pragma mark - GL Setup

View File

@ -168,8 +168,10 @@
TGPaintCanvas *canvas = (TGPaintCanvas *) recognizer.view;
TGPainting *painting = canvas.painting;
[painting performAsynchronouslyInContext:^{
painting.activePath = nil;
[canvas draw];
}];
}
- (void)paintPath:(TGPaintPath *)path inCanvas:(TGPaintCanvas *)canvas

View File

@ -16,7 +16,11 @@
- (void)touchesMoved:(NSSet *)inTouches withEvent:(UIEvent *)event
{
_touches = [inTouches copy];
if (inTouches.count > 1) {
self.state = UIGestureRecognizerStateCancelled;
} else {
[super touchesMoved:inTouches withEvent:event];
}
}
- (void)touchesEnded:(NSSet *)inTouches withEvent:(UIEvent *)event

View File

@ -168,7 +168,8 @@ typedef struct
for (f = state.remainder; f <= distance; f += step, pressure += pressureStep)
{
CGFloat alpha = boldenFirst ? boldenedAlpha : state.alpha;
CGFloat brushSize = MIN(brushWeight, brushWeight - pressure * brushWeight * 0.55f);
CGFloat brushSize = brushWeight;
// CGFloat brushSize = MIN(brushWeight, brushWeight - pressure * brushWeight * 0.55f);
[state addPoint:start size:brushSize angle:vectorAngle alpha:alpha index:i];
start = TGPaintAddPoints(start, TGPaintMultiplyPoint(unitVector, step));

View File

@ -27,6 +27,7 @@
- (instancetype)initWithSize:(CGSize)size undoManager:(TGPaintUndoManager *)undoManager imageData:(NSData *)imageData;
- (void)performSynchronouslyInContext:(void (^)(void))block;
- (void)performAsynchronouslyInContext:(void (^)(void))block;
- (void)paintStroke:(TGPaintPath *)path clearBuffer:(bool)clearBuffer completion:(void (^)(void))completion;

Some files were not shown because too many files have changed in this diff Show More