mirror of
https://github.com/TelegramMessenger/Telegram-iOS.git
synced 2026-07-06 03:33:41 +02:00
Merge commit '29fe4b3b09'
This commit is contained in:
commit
f6ca6f39ba
141 changed files with 3575 additions and 812 deletions
|
|
@ -45,6 +45,7 @@ framework_dependencies = [
|
|||
]
|
||||
|
||||
resource_dependencies = [
|
||||
"//submodules/LegacyComponents:LegacyComponentsAssets",
|
||||
"//submodules/LegacyComponents:LegacyComponentsResources",
|
||||
"//submodules/TelegramUI:TelegramUIAssets",
|
||||
"//submodules/TelegramUI:TelegramUIResources",
|
||||
|
|
|
|||
|
|
@ -156,6 +156,7 @@ swift_library(
|
|||
":AppIntentVocabularyResources",
|
||||
":InfoPlistStringResources",
|
||||
"//submodules/LegacyComponents:LegacyComponentsResources",
|
||||
"//submodules/LegacyComponents:LegacyComponentsAssets",
|
||||
"//submodules/OverlayStatusController:OverlayStatusControllerResources",
|
||||
"//submodules/PasswordSetupUI:PasswordSetupUIResources",
|
||||
"//submodules/PasswordSetupUI:PasswordSetupUIAssets",
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import Foundation
|
|||
import SwiftSignalKit
|
||||
import AsyncDisplayKit
|
||||
|
||||
enum AnimationRendererFrameType {
|
||||
public enum AnimationRendererFrameType {
|
||||
case argb
|
||||
case yuva
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,6 +8,14 @@ apple_resource(
|
|||
visibility = ["PUBLIC"],
|
||||
)
|
||||
|
||||
apple_asset_catalog(
|
||||
name = 'LegacyComponentsAssets',
|
||||
dirs = [
|
||||
"LegacyImages.xcassets",
|
||||
],
|
||||
visibility = ["PUBLIC"],
|
||||
)
|
||||
|
||||
static_library(
|
||||
name = "LegacyComponents",
|
||||
srcs = glob([
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"info" : {
|
||||
"version" : 1,
|
||||
"author" : "xcode"
|
||||
}
|
||||
}
|
||||
12
submodules/LegacyComponents/LegacyImages.xcassets/Editor/AddSticker.imageset/Contents.json
vendored
Normal file
12
submodules/LegacyComponents/LegacyImages.xcassets/Editor/AddSticker.imageset/Contents.json
vendored
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "ic_editor_addsticker.pdf",
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
Binary file not shown.
12
submodules/LegacyComponents/LegacyImages.xcassets/Editor/AddText.imageset/Contents.json
vendored
Normal file
12
submodules/LegacyComponents/LegacyImages.xcassets/Editor/AddText.imageset/Contents.json
vendored
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "ic_editor_addtext.pdf",
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
BIN
submodules/LegacyComponents/LegacyImages.xcassets/Editor/AddText.imageset/ic_editor_addtext.pdf
vendored
Normal file
BIN
submodules/LegacyComponents/LegacyImages.xcassets/Editor/AddText.imageset/ic_editor_addtext.pdf
vendored
Normal file
Binary file not shown.
12
submodules/LegacyComponents/LegacyImages.xcassets/Editor/Adjustments.imageset/Contents.json
vendored
Normal file
12
submodules/LegacyComponents/LegacyImages.xcassets/Editor/Adjustments.imageset/Contents.json
vendored
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "ic_editor_tools.pdf",
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
BIN
submodules/LegacyComponents/LegacyImages.xcassets/Editor/Adjustments.imageset/ic_editor_tools.pdf
vendored
Normal file
BIN
submodules/LegacyComponents/LegacyImages.xcassets/Editor/Adjustments.imageset/ic_editor_tools.pdf
vendored
Normal file
Binary file not shown.
12
submodules/LegacyComponents/LegacyImages.xcassets/Editor/AspectRatio.imageset/Contents.json
vendored
Normal file
12
submodules/LegacyComponents/LegacyImages.xcassets/Editor/AspectRatio.imageset/Contents.json
vendored
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "ic_editor_frame.pdf",
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
BIN
submodules/LegacyComponents/LegacyImages.xcassets/Editor/AspectRatio.imageset/ic_editor_frame.pdf
vendored
Normal file
BIN
submodules/LegacyComponents/LegacyImages.xcassets/Editor/AspectRatio.imageset/ic_editor_frame.pdf
vendored
Normal file
Binary file not shown.
12
submodules/LegacyComponents/LegacyImages.xcassets/Editor/Blur.imageset/Contents.json
vendored
Normal file
12
submodules/LegacyComponents/LegacyImages.xcassets/Editor/Blur.imageset/Contents.json
vendored
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "ic_editor_blur.pdf",
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
BIN
submodules/LegacyComponents/LegacyImages.xcassets/Editor/Blur.imageset/ic_editor_blur.pdf
vendored
Normal file
BIN
submodules/LegacyComponents/LegacyImages.xcassets/Editor/Blur.imageset/ic_editor_blur.pdf
vendored
Normal file
Binary file not shown.
12
submodules/LegacyComponents/LegacyImages.xcassets/Editor/Brush.imageset/Contents.json
vendored
Normal file
12
submodules/LegacyComponents/LegacyImages.xcassets/Editor/Brush.imageset/Contents.json
vendored
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "ic_editor_brushtype.pdf",
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
BIN
submodules/LegacyComponents/LegacyImages.xcassets/Editor/Brush.imageset/ic_editor_brushtype.pdf
vendored
Normal file
BIN
submodules/LegacyComponents/LegacyImages.xcassets/Editor/Brush.imageset/ic_editor_brushtype.pdf
vendored
Normal file
Binary file not shown.
12
submodules/LegacyComponents/LegacyImages.xcassets/Editor/Cancel.imageset/Contents.json
vendored
Normal file
12
submodules/LegacyComponents/LegacyImages.xcassets/Editor/Cancel.imageset/Contents.json
vendored
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "ic_editor_close (2).pdf",
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
BIN
submodules/LegacyComponents/LegacyImages.xcassets/Editor/Cancel.imageset/ic_editor_close (2).pdf
vendored
Normal file
BIN
submodules/LegacyComponents/LegacyImages.xcassets/Editor/Cancel.imageset/ic_editor_close (2).pdf
vendored
Normal file
Binary file not shown.
12
submodules/LegacyComponents/LegacyImages.xcassets/Editor/Commit.imageset/Contents.json
vendored
Normal file
12
submodules/LegacyComponents/LegacyImages.xcassets/Editor/Commit.imageset/Contents.json
vendored
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "ic_editor_check (2).pdf",
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
BIN
submodules/LegacyComponents/LegacyImages.xcassets/Editor/Commit.imageset/ic_editor_check (2).pdf
vendored
Normal file
BIN
submodules/LegacyComponents/LegacyImages.xcassets/Editor/Commit.imageset/ic_editor_check (2).pdf
vendored
Normal file
Binary file not shown.
|
|
@ -0,0 +1,9 @@
|
|||
{
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
},
|
||||
"properties" : {
|
||||
"provides-namespace" : true
|
||||
}
|
||||
}
|
||||
12
submodules/LegacyComponents/LegacyImages.xcassets/Editor/Crop.imageset/Contents.json
vendored
Normal file
12
submodules/LegacyComponents/LegacyImages.xcassets/Editor/Crop.imageset/Contents.json
vendored
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "ic_editor_crop.pdf",
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
BIN
submodules/LegacyComponents/LegacyImages.xcassets/Editor/Crop.imageset/ic_editor_crop.pdf
vendored
Normal file
BIN
submodules/LegacyComponents/LegacyImages.xcassets/Editor/Crop.imageset/ic_editor_crop.pdf
vendored
Normal file
Binary file not shown.
12
submodules/LegacyComponents/LegacyImages.xcassets/Editor/Curves.imageset/Contents.json
vendored
Normal file
12
submodules/LegacyComponents/LegacyImages.xcassets/Editor/Curves.imageset/Contents.json
vendored
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "ic_editor_curves.pdf",
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
BIN
submodules/LegacyComponents/LegacyImages.xcassets/Editor/Curves.imageset/ic_editor_curves.pdf
vendored
Normal file
BIN
submodules/LegacyComponents/LegacyImages.xcassets/Editor/Curves.imageset/ic_editor_curves.pdf
vendored
Normal file
Binary file not shown.
12
submodules/LegacyComponents/LegacyImages.xcassets/Editor/Drawing.imageset/Contents.json
vendored
Normal file
12
submodules/LegacyComponents/LegacyImages.xcassets/Editor/Drawing.imageset/Contents.json
vendored
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "ic_editor_brush.pdf",
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
BIN
submodules/LegacyComponents/LegacyImages.xcassets/Editor/Drawing.imageset/ic_editor_brush.pdf
vendored
Normal file
BIN
submodules/LegacyComponents/LegacyImages.xcassets/Editor/Drawing.imageset/ic_editor_brush.pdf
vendored
Normal file
Binary file not shown.
12
submodules/LegacyComponents/LegacyImages.xcassets/Editor/Eraser.imageset/Contents.json
vendored
Normal file
12
submodules/LegacyComponents/LegacyImages.xcassets/Editor/Eraser.imageset/Contents.json
vendored
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "ic_editor_eracer.pdf",
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
BIN
submodules/LegacyComponents/LegacyImages.xcassets/Editor/Eraser.imageset/ic_editor_eracer.pdf
vendored
Normal file
BIN
submodules/LegacyComponents/LegacyImages.xcassets/Editor/Eraser.imageset/ic_editor_eracer.pdf
vendored
Normal file
Binary file not shown.
12
submodules/LegacyComponents/LegacyImages.xcassets/Editor/Eyedropper.imageset/Contents.json
vendored
Normal file
12
submodules/LegacyComponents/LegacyImages.xcassets/Editor/Eyedropper.imageset/Contents.json
vendored
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "ic_editor_eyedropper.pdf",
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
Binary file not shown.
12
submodules/LegacyComponents/LegacyImages.xcassets/Editor/Flip.imageset/Contents.json
vendored
Normal file
12
submodules/LegacyComponents/LegacyImages.xcassets/Editor/Flip.imageset/Contents.json
vendored
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "ic_editor_flip.pdf",
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
BIN
submodules/LegacyComponents/LegacyImages.xcassets/Editor/Flip.imageset/ic_editor_flip.pdf
vendored
Normal file
BIN
submodules/LegacyComponents/LegacyImages.xcassets/Editor/Flip.imageset/ic_editor_flip.pdf
vendored
Normal file
Binary file not shown.
12
submodules/LegacyComponents/LegacyImages.xcassets/Editor/Font.imageset/Contents.json
vendored
Normal file
12
submodules/LegacyComponents/LegacyImages.xcassets/Editor/Font.imageset/Contents.json
vendored
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "ic_editor_font.pdf",
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
BIN
submodules/LegacyComponents/LegacyImages.xcassets/Editor/Font.imageset/ic_editor_font.pdf
vendored
Normal file
BIN
submodules/LegacyComponents/LegacyImages.xcassets/Editor/Font.imageset/ic_editor_font.pdf
vendored
Normal file
Binary file not shown.
12
submodules/LegacyComponents/LegacyImages.xcassets/Editor/Mute.imageset/Contents.json
vendored
Normal file
12
submodules/LegacyComponents/LegacyImages.xcassets/Editor/Mute.imageset/Contents.json
vendored
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "ic_editor_muted.pdf",
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
BIN
submodules/LegacyComponents/LegacyImages.xcassets/Editor/Mute.imageset/ic_editor_muted.pdf
vendored
Normal file
BIN
submodules/LegacyComponents/LegacyImages.xcassets/Editor/Mute.imageset/ic_editor_muted.pdf
vendored
Normal file
Binary file not shown.
12
submodules/LegacyComponents/LegacyImages.xcassets/Editor/Play.imageset/Contents.json
vendored
Normal file
12
submodules/LegacyComponents/LegacyImages.xcassets/Editor/Play.imageset/Contents.json
vendored
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "ic_editor_play.pdf",
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
BIN
submodules/LegacyComponents/LegacyImages.xcassets/Editor/Play.imageset/ic_editor_play.pdf
vendored
Normal file
BIN
submodules/LegacyComponents/LegacyImages.xcassets/Editor/Play.imageset/ic_editor_play.pdf
vendored
Normal file
Binary file not shown.
12
submodules/LegacyComponents/LegacyImages.xcassets/Editor/Recipient.imageset/Contents.json
vendored
Normal file
12
submodules/LegacyComponents/LegacyImages.xcassets/Editor/Recipient.imageset/Contents.json
vendored
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "send.pdf",
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
BIN
submodules/LegacyComponents/LegacyImages.xcassets/Editor/Recipient.imageset/send.pdf
vendored
Normal file
BIN
submodules/LegacyComponents/LegacyImages.xcassets/Editor/Recipient.imageset/send.pdf
vendored
Normal file
Binary file not shown.
12
submodules/LegacyComponents/LegacyImages.xcassets/Editor/Rotate.imageset/Contents.json
vendored
Normal file
12
submodules/LegacyComponents/LegacyImages.xcassets/Editor/Rotate.imageset/Contents.json
vendored
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "ic_editor_rotate.pdf",
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
BIN
submodules/LegacyComponents/LegacyImages.xcassets/Editor/Rotate.imageset/ic_editor_rotate.pdf
vendored
Normal file
BIN
submodules/LegacyComponents/LegacyImages.xcassets/Editor/Rotate.imageset/ic_editor_rotate.pdf
vendored
Normal file
Binary file not shown.
12
submodules/LegacyComponents/LegacyImages.xcassets/Editor/Tint.imageset/Contents.json
vendored
Normal file
12
submodules/LegacyComponents/LegacyImages.xcassets/Editor/Tint.imageset/Contents.json
vendored
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "ic_editor_tint.pdf",
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
BIN
submodules/LegacyComponents/LegacyImages.xcassets/Editor/Tint.imageset/ic_editor_tint.pdf
vendored
Normal file
BIN
submodules/LegacyComponents/LegacyImages.xcassets/Editor/Tint.imageset/ic_editor_tint.pdf
vendored
Normal file
Binary file not shown.
12
submodules/LegacyComponents/LegacyImages.xcassets/Editor/Undo.imageset/Contents.json
vendored
Normal file
12
submodules/LegacyComponents/LegacyImages.xcassets/Editor/Undo.imageset/Contents.json
vendored
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "ic_editor_undo.pdf",
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
BIN
submodules/LegacyComponents/LegacyImages.xcassets/Editor/Undo.imageset/ic_editor_undo.pdf
vendored
Normal file
BIN
submodules/LegacyComponents/LegacyImages.xcassets/Editor/Undo.imageset/ic_editor_undo.pdf
vendored
Normal file
Binary file not shown.
12
submodules/LegacyComponents/LegacyImages.xcassets/Editor/Unmute.imageset/Contents.json
vendored
Normal file
12
submodules/LegacyComponents/LegacyImages.xcassets/Editor/Unmute.imageset/Contents.json
vendored
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "ic_editor_unmuted.pdf",
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
BIN
submodules/LegacyComponents/LegacyImages.xcassets/Editor/Unmute.imageset/ic_editor_unmuted.pdf
vendored
Normal file
BIN
submodules/LegacyComponents/LegacyImages.xcassets/Editor/Unmute.imageset/ic_editor_unmuted.pdf
vendored
Normal file
Binary file not shown.
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -12,13 +12,16 @@
|
|||
|
||||
@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;
|
||||
|
||||
+ (SSignal *)renderUIImage:(UIImage *)image adjustments:(TGMediaVideoEditAdjustments *)adjustments watcher:(TGMediaVideoFileWatcher *)watcher entityRenderer:(id<TGPhotoPaintEntityRenderer>)entityRenderer;
|
||||
|
||||
+ (NSUInteger)estimatedSizeForPreset:(TGMediaVideoConversionPreset)preset duration:(NSTimeInterval)duration hasAudio:(bool)hasAudio;
|
||||
+ (TGMediaVideoConversionPreset)bestAvailablePresetForDimensions:(CGSize)dimensions;
|
||||
+ (CGSize)_renderSizeWithCropSize:(CGSize)cropSize;
|
||||
|
|
|
|||
|
|
@ -7,4 +7,6 @@
|
|||
@property (nonatomic, copy) void (^singleTapped)();
|
||||
@property (nonatomic, copy) void (^doubleTapped)(CGPoint point);
|
||||
|
||||
- (instancetype)initWithFrame:(CGRect)frame hasDoubleTap:(bool)hasDoubleTap;
|
||||
|
||||
@end
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -18,7 +18,6 @@
|
|||
|
||||
+ (UIColor *)editorButtonSelectionBackgroundColor;
|
||||
|
||||
+ (UIImage *)captionIcon;
|
||||
+ (UIImage *)cropIcon;
|
||||
+ (UIImage *)toolsIcon;
|
||||
+ (UIImage *)rotateIcon;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
#import <AVFoundation/AVFoundation.h>
|
||||
#import <LegacyComponents/TGMediaEditingContext.h>
|
||||
|
||||
@class PGPhotoEditorValues;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
TGMediaVideoConversionPresetCompressedDefault,
|
||||
|
|
@ -29,7 +31,7 @@ typedef enum
|
|||
|
||||
- (instancetype)editAdjustmentsWithPreset:(TGMediaVideoConversionPreset)preset maxDuration:(NSTimeInterval)maxDuration;
|
||||
+ (instancetype)editAdjustmentsWithOriginalSize:(CGSize)originalSize preset:(TGMediaVideoConversionPreset)preset;
|
||||
|
||||
+ (instancetype)editAdjustmentsWithPhotoEditorValues:(PGPhotoEditorValues *)values;
|
||||
+ (instancetype)editAdjustmentsWithDictionary:(NSDictionary *)dictionary;
|
||||
|
||||
+ (instancetype)editAdjustmentsWithOriginalSize:(CGSize)originalSize
|
||||
|
|
|
|||
Binary file not shown.
|
|
@ -200,6 +200,29 @@ NSString *const kGPUImagePassthroughFragmentShaderString = SHADER_STRING
|
|||
return image;
|
||||
}
|
||||
|
||||
- (CIImage *)newCIImageFromCurrentlyProcessedOutput {
|
||||
// Give it three seconds to process, then abort if they forgot to set up the image capture properly
|
||||
double timeoutForImageCapture = 3.0;
|
||||
dispatch_time_t convertedTimeout = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(timeoutForImageCapture * NSEC_PER_SEC));
|
||||
|
||||
if (dispatch_semaphore_wait(imageCaptureSemaphore, convertedTimeout) != 0)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
GPUImageFramebuffer* framebuffer = [self framebufferForOutput];
|
||||
|
||||
usingNextFrameForImageCapture = NO;
|
||||
dispatch_semaphore_signal(imageCaptureSemaphore);
|
||||
|
||||
CIImage *image = [framebuffer newCIImageFromFramebufferContents];
|
||||
return image;
|
||||
}
|
||||
|
||||
- (void)commitImageCapture {
|
||||
dispatch_semaphore_signal(imageCaptureSemaphore);
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Managing the display FBOs
|
||||
|
||||
|
|
|
|||
|
|
@ -1,17 +1,12 @@
|
|||
#import <Foundation/Foundation.h>
|
||||
|
||||
#if TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE
|
||||
#import <OpenGLES/EAGL.h>
|
||||
#import <OpenGLES/ES2/gl.h>
|
||||
#import <OpenGLES/ES2/glext.h>
|
||||
#else
|
||||
#import <OpenGL/OpenGL.h>
|
||||
#import <OpenGL/gl.h>
|
||||
#endif
|
||||
|
||||
#import <QuartzCore/QuartzCore.h>
|
||||
#import <CoreMedia/CoreMedia.h>
|
||||
|
||||
#import <CoreImage/CoreImage.h>
|
||||
|
||||
typedef struct GPUTextureOptions {
|
||||
GLenum minFilter;
|
||||
|
|
@ -49,6 +44,7 @@ typedef struct GPUTextureOptions {
|
|||
|
||||
// Image capture
|
||||
- (CGImageRef)newCGImageFromFramebufferContents;
|
||||
- (CIImage *)newCIImageFromFramebufferContents;
|
||||
- (void)restoreRenderTarget;
|
||||
|
||||
// Raw data bytes
|
||||
|
|
@ -57,4 +53,6 @@ typedef struct GPUTextureOptions {
|
|||
- (NSUInteger)bytesPerRow;
|
||||
- (GLubyte *)byteBuffer;
|
||||
|
||||
+ (void)setMark:(BOOL)mark;
|
||||
|
||||
@end
|
||||
|
|
|
|||
|
|
@ -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
|
||||
{
|
||||
|
|
@ -381,6 +380,75 @@ void dataProviderUnlockCallback (void *info, __unused const void *data, __unused
|
|||
return cgImageFromBytes;
|
||||
}
|
||||
|
||||
- (CIImage *)newCIImageFromFramebufferContents
|
||||
{
|
||||
// a CGImage can only be created from a 'normal' color texture
|
||||
NSAssert(self.textureOptions.internalFormat == GL_RGBA, @"For conversion to a CGImage the output texture format for this filter must be GL_RGBA.");
|
||||
NSAssert(self.textureOptions.type == GL_UNSIGNED_BYTE, @"For conversion to a CGImage the type of the output texture of this filter must be GL_UNSIGNED_BYTE.");
|
||||
|
||||
__block CIImage *ciImageFromBytes;
|
||||
|
||||
runSynchronouslyOnVideoProcessingQueue(^{
|
||||
[GPUImageContext useImageProcessingContext];
|
||||
|
||||
NSUInteger totalBytesForImage = (int)_size.width * (int)_size.height * 4;
|
||||
// It appears that the width of a texture must be padded out to be a multiple of 8 (32 bytes) if reading from it using a texture cache
|
||||
|
||||
|
||||
GLubyte *rawImagePixels;
|
||||
|
||||
CGDataProviderRef dataProvider = NULL;
|
||||
if ([GPUImageContext supportsFastTextureUpload])
|
||||
{
|
||||
NSUInteger paddedWidthOfImage = (NSUInteger)(CVPixelBufferGetBytesPerRow(renderTarget) / 4.0);
|
||||
NSUInteger paddedBytesForImage = paddedWidthOfImage * (int)_size.height * 4;
|
||||
|
||||
glFinish();
|
||||
CFRetain(renderTarget); // I need to retain the pixel buffer here and release in the data source callback to prevent its bytes from being prematurely deallocated during a photo write operation
|
||||
[self lockForReading];
|
||||
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
|
||||
|
||||
ciImageFromBytes = [[CIImage alloc] initWithCVPixelBuffer:renderTarget options:nil];
|
||||
|
||||
[self restoreRenderTarget];
|
||||
[self unlock];
|
||||
[[GPUImageContext sharedFramebufferCache] removeFramebufferFromActiveImageCaptureList:self];
|
||||
}
|
||||
// else
|
||||
// {
|
||||
// [self activateFramebuffer];
|
||||
// rawImagePixels = (GLubyte *)malloc(totalBytesForImage);
|
||||
// glReadPixels(0, 0, (int)_size.width, (int)_size.height, GL_RGBA, GL_UNSIGNED_BYTE, rawImagePixels);
|
||||
// dataProvider = CGDataProviderCreateWithData(NULL, rawImagePixels, totalBytesForImage, dataProviderReleaseCallback);
|
||||
// [self unlock]; // Don't need to keep this around anymore
|
||||
// }
|
||||
|
||||
// CGColorSpaceRef defaultRGBColorSpace = CGColorSpaceCreateDeviceRGB();
|
||||
//
|
||||
//
|
||||
// CIImage *image = [[CIImage alloc] initWithImageProvider:dataProvider size:<#(size_t)#> :<#(size_t)#> format:kCIFormatRGBA8 colorSpace:defaultRGBColorSpace options:<#(nullable NSDictionary<CIImageOption,id> *)#>]
|
||||
|
||||
// if ([GPUImageContext supportsFastTextureUpload])
|
||||
// {
|
||||
// cgImageFromBytes = CGImageCreate((int)_size.width, (int)_size.height, 8, 32, CVPixelBufferGetBytesPerRow(renderTarget), defaultRGBColorSpace, kCGBitmapByteOrder32Little | kCGImageAlphaPremultipliedFirst, dataProvider, NULL, NO, kCGRenderingIntentDefault);
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// cgImageFromBytes = CGImageCreate((int)_size.width, (int)_size.height, 8, 32, 4 * (int)_size.width, defaultRGBColorSpace, kCGBitmapByteOrderDefault | kCGImageAlphaPremultipliedLast, dataProvider, NULL, NO, kCGRenderingIntentDefault);
|
||||
// }
|
||||
|
||||
// Capture image with current device orientation
|
||||
// CGDataProviderRelease(dataProvider);
|
||||
// CGColorSpaceRelease(defaultRGBColorSpace);
|
||||
|
||||
});
|
||||
|
||||
return ciImageFromBytes;
|
||||
}
|
||||
|
||||
- (void)restoreRenderTarget
|
||||
{
|
||||
#if TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,21 +1,8 @@
|
|||
#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
|
||||
#import <CoreImage/CoreImage.h>
|
||||
|
||||
void runOnMainQueueWithoutDeadlocking(void (^block)(void));
|
||||
void runSynchronouslyOnVideoProcessingQueue(void (^block)(void));
|
||||
|
|
@ -24,17 +11,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 +32,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;
|
||||
|
|
@ -105,16 +80,11 @@ void reportAvailableMemoryForGPUImage(NSString *tag);
|
|||
|
||||
- (void)useNextFrameForImageCapture;
|
||||
- (CGImageRef)newCGImageFromCurrentlyProcessedOutput;
|
||||
- (CIImage *)newCIImageFromCurrentlyProcessedOutput;
|
||||
- (void)commitImageCapture;
|
||||
|
||||
// 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;
|
||||
|
||||
|
|
|
|||
|
|
@ -278,6 +278,15 @@ void reportAvailableMemoryForGPUImage(NSString *tag)
|
|||
return nil;
|
||||
}
|
||||
|
||||
- (CIImage *)newCIImageFromCurrentlyProcessedOutput {
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (void)commitImageCapture
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
- (BOOL)providesMonochromeOutput
|
||||
{
|
||||
return NO;
|
||||
|
|
|
|||
16
submodules/LegacyComponents/Sources/GPUImageTextureInput.h
Executable file
16
submodules/LegacyComponents/Sources/GPUImageTextureInput.h
Executable 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
|
||||
94
submodules/LegacyComponents/Sources/GPUImageTextureInput.m
Executable file
94
submodules/LegacyComponents/Sources/GPUImageTextureInput.m
Executable 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: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
|
||||
24
submodules/LegacyComponents/Sources/GPUImageTextureOutput.h
Executable file
24
submodules/LegacyComponents/Sources/GPUImageTextureOutput.h
Executable 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
|
||||
94
submodules/LegacyComponents/Sources/GPUImageTextureOutput.m
Executable file
94
submodules/LegacyComponents/Sources/GPUImageTextureOutput.m
Executable file
|
|
@ -0,0 +1,94 @@
|
|||
#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
|
||||
{
|
||||
EAGLContext *context = [[GPUImageContext sharedImageProcessingContext] context];
|
||||
[EAGLContext setCurrentContext:context];
|
||||
|
||||
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
|
||||
|
|
@ -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];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -31,23 +31,31 @@
|
|||
|
||||
@property (nonatomic, readonly) bool forVideo;
|
||||
|
||||
@property (nonatomic, assign) bool standalone;
|
||||
|
||||
- (instancetype)initWithOriginalSize:(CGSize)originalSize adjustments:(id<TGMediaEditAdjustments>)adjustments forVideo:(bool)forVideo enableStickers:(bool)enableStickers;
|
||||
|
||||
- (void)cleanup;
|
||||
|
||||
- (void)setImage:(UIImage *)image forCropRect:(CGRect)cropRect cropRotation:(CGFloat)cropRotation cropOrientation:(UIImageOrientation)cropOrientation cropMirrored:(bool)cropMirrored fullSize:(bool)fullSize;
|
||||
- (void)setVideoAsset:(AVAsset *)asset;
|
||||
- (void)setPlayerItem:(AVPlayerItem *)playerItem;
|
||||
- (void)setCIImage:(CIImage *)ciImage;
|
||||
|
||||
- (void)processAnimated:(bool)animated completion:(void (^)(void))completion;
|
||||
|
||||
- (void)createResultImageWithCompletion:(void (^)(UIImage *image))completion;
|
||||
- (UIImage *)currentResultImage;
|
||||
- (CIImage *)currentResultCIImage;
|
||||
|
||||
- (bool)hasDefaultCropping;
|
||||
|
||||
- (SSignal *)histogramSignal;
|
||||
|
||||
- (void)importAdjustments:(id<TGMediaEditAdjustments>)adjustments;
|
||||
- (id<TGMediaEditAdjustments>)exportAdjustments;
|
||||
- (id<TGMediaEditAdjustments>)exportAdjustmentsWithPaintingData:(TGPaintingData *)paintingData;
|
||||
|
||||
+ (UIImage *)resultImageForImage:(UIImage *)image adjustments:(id<TGMediaEditAdjustments>)adjustments;
|
||||
|
||||
@end
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
@ -101,7 +106,7 @@
|
|||
strongSelf->_histogramPipe.sink(histogram);
|
||||
};
|
||||
|
||||
[self _importAdjustments:adjustments];
|
||||
[self importAdjustments:adjustments];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
|
@ -167,6 +172,32 @@
|
|||
_fullSize = true;
|
||||
}
|
||||
|
||||
- (void)setPlayerItem:(AVPlayerItem *)playerItem {
|
||||
[_toolComposer invalidate];
|
||||
_currentProcessChain = nil;
|
||||
|
||||
[_currentInput removeAllTargets];
|
||||
PGVideoMovie *movie = [[PGVideoMovie alloc] initWithPlayerItem:playerItem];
|
||||
_currentInput = movie;
|
||||
|
||||
_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 +232,7 @@
|
|||
|
||||
- (void)processAnimated:(bool)animated capture:(bool)capture synchronous:(bool)synchronous completion:(void (^)(void))completion
|
||||
{
|
||||
if (self.previewOutput == nil)
|
||||
if (self.previewOutput == nil && !self.standalone)
|
||||
return;
|
||||
|
||||
if (self.forVideo) {
|
||||
|
|
@ -210,16 +241,25 @@
|
|||
[self updateProcessChain];
|
||||
|
||||
GPUImageOutput *currentInput = _currentInput;
|
||||
|
||||
if (!_playing) {
|
||||
_playing = true;
|
||||
[_videoQueue dispatch:^{
|
||||
if ([currentInput isKindOfClass:[PGVideoMovie class]]) {
|
||||
[(PGVideoMovie *)currentInput startProcessing];
|
||||
}
|
||||
}];
|
||||
if ([currentInput isKindOfClass:[PGVideoMovie class]]) {
|
||||
if (!_playing) {
|
||||
_playing = true;
|
||||
[_videoQueue dispatch:^{
|
||||
if ([currentInput isKindOfClass:[PGVideoMovie class]]) {
|
||||
[(PGVideoMovie *)currentInput startProcessing];
|
||||
}
|
||||
}];
|
||||
}
|
||||
} else if ([currentInput isKindOfClass:[GPUImageTextureInput class]]) {
|
||||
if (capture)
|
||||
[_finalFilter useNextFrameForImageCapture];
|
||||
|
||||
[(GPUImageTextureInput *)currentInput processTextureWithFrameTime:kCMTimeZero synchronous:synchronous];
|
||||
if (completion != nil)
|
||||
completion();
|
||||
[_finalFilter commitImageCapture];
|
||||
}
|
||||
}];
|
||||
} synchronous:synchronous];
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -281,6 +321,8 @@
|
|||
}
|
||||
|
||||
- (void)updateProcessChain {
|
||||
[GPUImageFramebuffer setMark:self.forVideo];
|
||||
|
||||
NSMutableArray *processChain = [NSMutableArray array];
|
||||
|
||||
for (PGPhotoTool *tool in _toolComposer.advancedTools)
|
||||
|
|
@ -319,10 +361,17 @@
|
|||
}
|
||||
_finalFilter = lastFilter;
|
||||
|
||||
[_finalFilter addTarget:previewOutput.imageView];
|
||||
if (_textureOutput != nil) {
|
||||
[_finalFilter addTarget:_textureOutput];
|
||||
}
|
||||
|
||||
if (previewOutput != nil) {
|
||||
[_finalFilter addTarget:previewOutput.imageView];
|
||||
}
|
||||
|
||||
if (!self.forVideo)
|
||||
if (!self.forVideo) {
|
||||
[_finalFilter addTarget:_histogramGenerator];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -349,9 +398,22 @@
|
|||
return image;
|
||||
}
|
||||
|
||||
- (CIImage *)currentResultCIImage {
|
||||
__block CIImage *image = nil;
|
||||
GPUImageOutput *currentInput = _currentInput;
|
||||
[self processAnimated:false capture:true synchronous:true completion:^
|
||||
{
|
||||
image = [_finalFilter newCIImageFromCurrentlyProcessedOutput];
|
||||
// if ([currentInput isKindOfClass:[GPUImageTextureInput class]]) {
|
||||
// image = [_textureOutput CIImageWithSize:[(GPUImageTextureInput *)currentInput textureSize]];
|
||||
// }
|
||||
}];
|
||||
return image;
|
||||
}
|
||||
|
||||
#pragma mark - Editor Values
|
||||
|
||||
- (void)_importAdjustments:(id<TGMediaEditAdjustments>)adjustments
|
||||
- (void)importAdjustments:(id<TGMediaEditAdjustments>)adjustments
|
||||
{
|
||||
_initialAdjustments = adjustments;
|
||||
|
||||
|
|
@ -445,4 +507,11 @@
|
|||
return tools;
|
||||
}
|
||||
|
||||
+ (UIImage *)resultImageForImage:(UIImage *)image adjustments:(id<TGMediaEditAdjustments>)adjustments {
|
||||
PGPhotoEditor *editor = [[PGPhotoEditor alloc] initWithOriginalSize:adjustments.originalSize adjustments:adjustments forVideo:false enableStickers:true];
|
||||
editor.standalone = true;
|
||||
[editor setImage:image forCropRect:adjustments.cropRect cropRotation:0.0 cropOrientation:adjustments.cropOrientation cropMirrored:adjustments.cropMirrored fullSize:false];
|
||||
return [editor currentResultImage];
|
||||
}
|
||||
|
||||
@end
|
||||
|
|
|
|||
|
|
@ -172,7 +172,7 @@ const NSUInteger PGPhotoEnhanceSegments = 4;
|
|||
NSUInteger hMin = PGPhotoEnhanceHistogramBins - 1;
|
||||
for (NSUInteger j = 0; j < hMin; ++j)
|
||||
{
|
||||
if (cdfs[j] != 0)
|
||||
if (cdfs[i][j] != 0)
|
||||
hMin = j;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -6,18 +6,18 @@
|
|||
@interface PGVideoMovie : GPUImageOutput
|
||||
|
||||
@property (readwrite, retain) AVAsset *asset;
|
||||
@property (readwrite, retain) AVPlayerItem *playerItem;
|
||||
@property (nonatomic, assign) bool shouldRepeat;
|
||||
|
||||
@property (readonly, nonatomic) CGFloat progress;
|
||||
|
||||
@property (readonly, nonatomic) AVAssetReader *assetReader;
|
||||
@property (readonly, nonatomic) bool audioEncodingIsFinished;
|
||||
@property (readonly, nonatomic) bool videoEncodingIsFinished;
|
||||
|
||||
- (instancetype)initWithAsset:(AVAsset *)asset;
|
||||
- (instancetype)initWithPlayerItem:(AVPlayerItem *)playerItem;
|
||||
|
||||
- (BOOL)readNextVideoFrameFromOutput:(AVAssetReaderOutput *)readerVideoTrackOutput;
|
||||
- (BOOL)readNextAudioSampleFromOutput:(AVAssetReaderOutput *)readerAudioTrackOutput;
|
||||
- (void)startProcessing;
|
||||
- (void)endProcessing;
|
||||
- (void)cancelProcessing;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
@ -89,8 +89,6 @@ NSString *const kYUVVideoRangeConversionForLAFragmentShaderString = SHADER_STRIN
|
|||
|
||||
@interface PGVideoMovie () <AVPlayerItemOutputPullDelegate>
|
||||
{
|
||||
BOOL audioEncodingIsFinished, videoEncodingIsFinished;
|
||||
// GPUImageMovieWriter *synchronizedMovieWriter;
|
||||
AVAssetReader *reader;
|
||||
AVPlayerItemVideoOutput *playerItemOutput;
|
||||
CADisplayLink *displayLink;
|
||||
|
|
@ -116,6 +114,9 @@ NSString *const kYUVVideoRangeConversionForLAFragmentShaderString = SHADER_STRIN
|
|||
@end
|
||||
|
||||
@implementation PGVideoMovie
|
||||
{
|
||||
bool videoEncodingIsFinished;
|
||||
}
|
||||
|
||||
@synthesize asset = _asset;
|
||||
@synthesize shouldRepeat = _shouldRepeat;
|
||||
|
|
@ -123,8 +124,23 @@ NSString *const kYUVVideoRangeConversionForLAFragmentShaderString = SHADER_STRIN
|
|||
#pragma mark -
|
||||
#pragma mark Initialization and teardown
|
||||
|
||||
- (UIInterfaceOrientation)orientationForTrack:(AVAsset *)asset
|
||||
{
|
||||
AVAssetTrack *videoTrack = [[asset tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0];
|
||||
CGSize size = [videoTrack naturalSize];
|
||||
CGAffineTransform txf = [videoTrack preferredTransform];
|
||||
|
||||
- (instancetype)initWithAsset:(AVAsset *)asset;
|
||||
if (size.width == txf.tx && size.height == txf.ty)
|
||||
return UIInterfaceOrientationLandscapeRight;
|
||||
else if (txf.tx == 0 && txf.ty == 0)
|
||||
return UIInterfaceOrientationLandscapeLeft;
|
||||
else if (txf.tx == 0 && txf.ty == size.width)
|
||||
return UIInterfaceOrientationPortraitUpsideDown;
|
||||
else
|
||||
return UIInterfaceOrientationPortrait;
|
||||
}
|
||||
|
||||
- (instancetype)initWithAsset:(AVAsset *)asset
|
||||
{
|
||||
if (!(self = [super init]))
|
||||
{
|
||||
|
|
@ -138,7 +154,21 @@ NSString *const kYUVVideoRangeConversionForLAFragmentShaderString = SHADER_STRIN
|
|||
return self;
|
||||
}
|
||||
|
||||
- (void)yuvConversionSetup;
|
||||
- (instancetype)initWithPlayerItem:(AVPlayerItem *)playerItem;
|
||||
{
|
||||
if (!(self = [super init]))
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
|
||||
[self yuvConversionSetup];
|
||||
|
||||
self.playerItem = playerItem;
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)yuvConversionSetup
|
||||
{
|
||||
if ([GPUImageContext supportsFastTextureUpload])
|
||||
{
|
||||
|
|
@ -147,7 +177,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)
|
||||
{
|
||||
|
|
@ -185,12 +215,11 @@ NSString *const kYUVVideoRangeConversionForLAFragmentShaderString = SHADER_STRIN
|
|||
{
|
||||
[playerItemOutput setDelegate:nil queue:nil];
|
||||
|
||||
// Moved into endProcessing
|
||||
//if (self.playerItem && (displayLink != nil))
|
||||
//{
|
||||
// [displayLink invalidate]; // remove from all run loops
|
||||
// displayLink = nil;
|
||||
//}
|
||||
if (self.playerItem && (displayLink != nil))
|
||||
{
|
||||
[displayLink invalidate];
|
||||
displayLink = nil;
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
|
|
@ -206,14 +235,18 @@ NSString *const kYUVVideoRangeConversionForLAFragmentShaderString = SHADER_STRIN
|
|||
{
|
||||
if (_shouldRepeat) self->keepLooping = true;
|
||||
|
||||
[self processAsset];
|
||||
if (self.playerItem != nil) {
|
||||
[self processPlayerItem];
|
||||
} else {
|
||||
[self processAsset];
|
||||
}
|
||||
}
|
||||
|
||||
- (AVAssetReader*)createAssetReader
|
||||
{
|
||||
NSError *error = nil;
|
||||
AVAssetReader *assetReader = [AVAssetReader assetReaderWithAsset:self.asset error:&error];
|
||||
|
||||
|
||||
NSMutableDictionary *outputSettings = [NSMutableDictionary dictionary];
|
||||
if ([GPUImageContext supportsFastTextureUpload]) {
|
||||
[outputSettings setObject:@(kCVPixelFormatType_420YpCbCr8BiPlanarFullRange) forKey:(id)kCVPixelBufferPixelFormatTypeKey];
|
||||
|
|
@ -224,26 +257,10 @@ 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;
|
||||
readerVideoTrackOutput.alwaysCopiesSampleData = false;
|
||||
[assetReader addOutput:readerVideoTrackOutput];
|
||||
|
||||
// NSArray *audioTracks = [self.asset tracksWithMediaType:AVMediaTypeAudio];
|
||||
// BOOL shouldRecordAudioTrack = (([audioTracks count] > 0) && (self.audioEncodingTarget != nil) );
|
||||
// AVAssetReaderTrackOutput *readerAudioTrackOutput = nil;
|
||||
//
|
||||
// if (shouldRecordAudioTrack)
|
||||
// {
|
||||
// [self.audioEncodingTarget setShouldInvalidateAudioSampleWhenDone:YES];
|
||||
//
|
||||
// // This might need to be extended to handle movies with more than one audio track
|
||||
// AVAssetTrack* audioTrack = [audioTracks objectAtIndex:0];
|
||||
// readerAudioTrackOutput = [AVAssetReaderTrackOutput assetReaderTrackOutputWithTrack:audioTrack outputSettings:nil];
|
||||
// readerAudioTrackOutput.alwaysCopiesSampleData = NO;
|
||||
// [assetReader addOutput:readerAudioTrackOutput];
|
||||
// }
|
||||
|
||||
return assetReader;
|
||||
}
|
||||
|
||||
|
|
@ -252,65 +269,62 @@ NSString *const kYUVVideoRangeConversionForLAFragmentShaderString = SHADER_STRIN
|
|||
reader = [self createAssetReader];
|
||||
|
||||
AVAssetReaderOutput *readerVideoTrackOutput = nil;
|
||||
AVAssetReaderOutput *readerAudioTrackOutput = nil;
|
||||
|
||||
audioEncodingIsFinished = YES;
|
||||
for( AVAssetReaderOutput *output in reader.outputs ) {
|
||||
if( [output.mediaType isEqualToString:AVMediaTypeAudio] ) {
|
||||
audioEncodingIsFinished = NO;
|
||||
readerAudioTrackOutput = output;
|
||||
}
|
||||
else if( [output.mediaType isEqualToString:AVMediaTypeVideo] ) {
|
||||
|
||||
for (AVAssetReaderOutput *output in reader.outputs) {
|
||||
if( [output.mediaType isEqualToString:AVMediaTypeVideo] ) {
|
||||
readerVideoTrackOutput = output;
|
||||
}
|
||||
}
|
||||
|
||||
if ([reader startReading] == NO) {
|
||||
if (![reader startReading]) {
|
||||
return;
|
||||
}
|
||||
|
||||
__unsafe_unretained PGVideoMovie *weakSelf = self;
|
||||
|
||||
// if (synchronizedMovieWriter != nil)
|
||||
// {
|
||||
// [synchronizedMovieWriter setVideoInputReadyCallback:^{
|
||||
// BOOL success = [weakSelf readNextVideoFrameFromOutput:readerVideoTrackOutput];
|
||||
// return success;
|
||||
// }];
|
||||
//
|
||||
// [synchronizedMovieWriter setAudioInputReadyCallback:^{
|
||||
// BOOL success = [weakSelf readNextAudioSampleFromOutput:readerAudioTrackOutput];
|
||||
// return success;
|
||||
// }];
|
||||
//
|
||||
// [synchronizedMovieWriter enableSynchronizationCallbacks];
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
while (reader.status == AVAssetReaderStatusReading && (!_shouldRepeat || keepLooping))
|
||||
{
|
||||
[weakSelf readNextVideoFrameFromOutput:readerVideoTrackOutput];
|
||||
while (reader.status == AVAssetReaderStatusReading && (!_shouldRepeat || keepLooping))
|
||||
{
|
||||
[weakSelf readNextVideoFrameFromOutput:readerVideoTrackOutput];
|
||||
}
|
||||
|
||||
if ((readerAudioTrackOutput) && (!audioEncodingIsFinished))
|
||||
{
|
||||
[weakSelf readNextAudioSampleFromOutput:readerAudioTrackOutput];
|
||||
}
|
||||
if (reader.status == AVAssetReaderStatusCompleted) {
|
||||
|
||||
[reader cancelReading];
|
||||
|
||||
if (keepLooping) {
|
||||
reader = nil;
|
||||
[self startProcessing];
|
||||
} else {
|
||||
[weakSelf endProcessing];
|
||||
}
|
||||
|
||||
if (reader.status == AVAssetReaderStatusCompleted) {
|
||||
|
||||
[reader cancelReading];
|
||||
}
|
||||
}
|
||||
|
||||
if (keepLooping) {
|
||||
reader = nil;
|
||||
[self startProcessing];
|
||||
} else {
|
||||
[weakSelf endProcessing];
|
||||
}
|
||||
- (void)processPlayerItem
|
||||
{
|
||||
dispatch_sync(dispatch_get_main_queue(), ^{
|
||||
displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(displayLinkCallback:)];
|
||||
[displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes];
|
||||
[displayLink setPaused:true];
|
||||
});
|
||||
|
||||
|
||||
runSynchronouslyOnVideoProcessingQueue(^{
|
||||
dispatch_queue_t videoProcessingQueue = [GPUImageContext sharedContextQueue];
|
||||
NSMutableDictionary *pixBuffAttributes = [NSMutableDictionary dictionary];
|
||||
if ([GPUImageContext supportsFastTextureUpload]) {
|
||||
[pixBuffAttributes setObject:@(kCVPixelFormatType_420YpCbCr8BiPlanarFullRange) forKey:(id)kCVPixelBufferPixelFormatTypeKey];
|
||||
}
|
||||
// }
|
||||
else {
|
||||
[pixBuffAttributes setObject:@(kCVPixelFormatType_32BGRA) forKey:(id)kCVPixelBufferPixelFormatTypeKey];
|
||||
}
|
||||
playerItemOutput = [[AVPlayerItemVideoOutput alloc] initWithPixelBufferAttributes:pixBuffAttributes];
|
||||
[playerItemOutput setDelegate:self queue:videoProcessingQueue];
|
||||
|
||||
[_playerItem addOutput:playerItemOutput];
|
||||
[playerItemOutput requestNotificationOfMediaDataChangeWithAdvanceInterval:0.1];
|
||||
});
|
||||
}
|
||||
|
||||
- (void)outputMediaDataWillChange:(AVPlayerItemOutput *)sender
|
||||
|
|
@ -323,7 +337,6 @@ NSString *const kYUVVideoRangeConversionForLAFragmentShaderString = SHADER_STRIN
|
|||
CFTimeInterval nextVSync = ([sender timestamp] + [sender duration]);
|
||||
CMTime outputItemTime = [playerItemOutput itemTimeForHostTime:nextVSync];
|
||||
[self processPixelBufferAtTime:outputItemTime];
|
||||
|
||||
}
|
||||
|
||||
- (void)processPixelBufferAtTime:(CMTime)outputItemTime
|
||||
|
|
@ -371,56 +384,20 @@ NSString *const kYUVVideoRangeConversionForLAFragmentShaderString = SHADER_STRIN
|
|||
CFRelease(sampleBufferRef);
|
||||
});
|
||||
|
||||
return YES;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!keepLooping) {
|
||||
videoEncodingIsFinished = YES;
|
||||
if( videoEncodingIsFinished && audioEncodingIsFinished )
|
||||
videoEncodingIsFinished = true;
|
||||
if (videoEncodingIsFinished)
|
||||
[self endProcessing];
|
||||
}
|
||||
}
|
||||
}
|
||||
// else if (synchronizedMovieWriter != nil)
|
||||
// {
|
||||
// if (reader.status == AVAssetReaderStatusCompleted)
|
||||
// {
|
||||
// [self endProcessing];
|
||||
// }
|
||||
// }
|
||||
return NO;
|
||||
return false;
|
||||
}
|
||||
|
||||
- (BOOL)readNextAudioSampleFromOutput:(AVAssetReaderOutput *)readerAudioTrackOutput;
|
||||
{
|
||||
if (reader.status == AVAssetReaderStatusReading && ! audioEncodingIsFinished)
|
||||
{
|
||||
CMSampleBufferRef audioSampleBufferRef = [readerAudioTrackOutput copyNextSampleBuffer];
|
||||
if (audioSampleBufferRef)
|
||||
{
|
||||
CFRelease(audioSampleBufferRef);
|
||||
return YES;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!keepLooping) {
|
||||
audioEncodingIsFinished = YES;
|
||||
if (videoEncodingIsFinished && audioEncodingIsFinished)
|
||||
[self endProcessing];
|
||||
}
|
||||
}
|
||||
}
|
||||
// else if (synchronizedMovieWriter != nil)
|
||||
// {
|
||||
// if (reader.status == AVAssetReaderStatusCompleted || reader.status == AVAssetReaderStatusFailed ||
|
||||
// reader.status == AVAssetReaderStatusCancelled)
|
||||
// {
|
||||
// [self endProcessing];
|
||||
// }
|
||||
// }
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (void)processMovieFrame:(CMSampleBufferRef)movieSampleBuffer;
|
||||
{
|
||||
|
|
@ -485,8 +462,6 @@ NSString *const kYUVVideoRangeConversionForLAFragmentShaderString = SHADER_STRIN
|
|||
}
|
||||
|
||||
}
|
||||
|
||||
CFAbsoluteTime startTime = CFAbsoluteTimeGetCurrent();
|
||||
|
||||
[GPUImageContext useImageProcessingContext];
|
||||
|
||||
|
|
@ -510,7 +485,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 +506,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 +531,21 @@ NSString *const kYUVVideoRangeConversionForLAFragmentShaderString = SHADER_STRIN
|
|||
NSInteger targetTextureIndex = [[targetTextureIndices objectAtIndex:indexOfObject] integerValue];
|
||||
[currentTarget setInputSize:CGSizeMake(bufferWidth, bufferHeight) atIndex:targetTextureIndex];
|
||||
[currentTarget setInputFramebuffer:outputFramebuffer atIndex:targetTextureIndex];
|
||||
|
||||
AVAsset *asset = self.asset;
|
||||
if (asset == nil) {
|
||||
asset = self.playerItem.asset;
|
||||
}
|
||||
if (asset != nil) {
|
||||
UIInterfaceOrientation orientation = [self orientationForTrack:asset];
|
||||
if (orientation == UIInterfaceOrientationPortrait) {
|
||||
[currentTarget setInputRotation:kGPUImageRotateRight atIndex:targetTextureIndex];
|
||||
} else if (orientation == UIInterfaceOrientationLandscapeRight) {
|
||||
[currentTarget setInputRotation:kGPUImageRotate180 atIndex:targetTextureIndex];
|
||||
} else if (orientation == UIInterfaceOrientationPortraitUpsideDown) {
|
||||
[currentTarget setInputRotation:kGPUImageRotateLeft atIndex:targetTextureIndex];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[outputFramebuffer unlock];
|
||||
|
|
@ -671,10 +661,6 @@ NSString *const kYUVVideoRangeConversionForLAFragmentShaderString = SHADER_STRIN
|
|||
return reader;
|
||||
}
|
||||
|
||||
- (BOOL)audioEncodingIsFinished {
|
||||
return audioEncodingIsFinished;
|
||||
}
|
||||
|
||||
- (BOOL)videoEncodingIsFinished {
|
||||
return videoEncodingIsFinished;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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];
|
||||
|
|
|
|||
|
|
@ -27,6 +27,8 @@
|
|||
#import <LegacyComponents/TGVideoEditAdjustments.h>
|
||||
#import <LegacyComponents/TGPaintingData.h>
|
||||
|
||||
#import "PGPhotoEditor.h"
|
||||
|
||||
@interface TGMediaAssetsController () <UINavigationControllerDelegate, ASWatcher>
|
||||
{
|
||||
TGMediaAssetsControllerIntent _intent;
|
||||
|
|
@ -110,6 +112,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 +152,12 @@
|
|||
self.pickerController.suggestionContext = suggestionContext;
|
||||
}
|
||||
|
||||
- (void)setStickersContext:(id<TGPhotoPaintStickersContext>)stickersContext
|
||||
{
|
||||
_stickersContext = stickersContext;
|
||||
self.pickerController.stickersContext = stickersContext;
|
||||
}
|
||||
|
||||
- (void)setCaptionsEnabled:(bool)captionsEnabled
|
||||
{
|
||||
_captionsEnabled = captionsEnabled;
|
||||
|
|
@ -812,10 +821,48 @@
|
|||
NSMutableDictionary *dict = [[NSMutableDictionary alloc] init];
|
||||
dict[@"type"] = @"editedPhoto";
|
||||
dict[@"image"] = image;
|
||||
|
||||
if (adjustments.paintingData.stickers.count > 0)
|
||||
dict[@"stickers"] = adjustments.paintingData.stickers;
|
||||
|
||||
bool animated = false;
|
||||
for (TGPhotoPaintEntity *entity in adjustments.paintingData.entities) {
|
||||
if (entity.animated) {
|
||||
animated = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (animated) {
|
||||
dict[@"isAnimation"] = @true;
|
||||
if ([adjustments isKindOfClass:[PGPhotoEditorValues class]]) {
|
||||
dict[@"adjustments"] = [TGVideoEditAdjustments editAdjustmentsWithPhotoEditorValues:(PGPhotoEditorValues *)adjustments];
|
||||
} else {
|
||||
dict[@"adjustments"] = adjustments;
|
||||
}
|
||||
|
||||
NSString *filePath = [NSTemporaryDirectory() stringByAppendingPathComponent:[[NSString alloc] initWithFormat:@"gifvideo_%x.jpg", (int)arc4random()]];
|
||||
NSData *data = UIImageJPEGRepresentation(image, 0.8);
|
||||
[data writeToFile:filePath atomically:true];
|
||||
dict[@"url"] = [NSURL fileURLWithPath:filePath];
|
||||
|
||||
|
||||
if ([adjustments cropAppliedForAvatar:false] || adjustments.hasPainting || adjustments.toolsApplied)
|
||||
{
|
||||
CGRect scaledCropRect = CGRectMake(adjustments.cropRect.origin.x * image.size.width / adjustments.originalSize.width, adjustments.cropRect.origin.y * image.size.height / adjustments.originalSize.height, adjustments.cropRect.size.width * image.size.width / adjustments.originalSize.width, adjustments.cropRect.size.height * image.size.height / adjustments.originalSize.height);
|
||||
UIImage *paintingImage = adjustments.paintingData.stillImage;
|
||||
if (paintingImage == nil) {
|
||||
paintingImage = adjustments.paintingData.image;
|
||||
}
|
||||
if (adjustments.toolsApplied) {
|
||||
image = [PGPhotoEditor resultImageForImage:image adjustments:adjustments];
|
||||
}
|
||||
UIImage *thumbnailImage = TGPhotoEditorCrop(image, paintingImage, adjustments.cropOrientation, 0, scaledCropRect, adjustments.cropMirrored, TGScaleToFill(asset.dimensions, CGSizeMake(384, 384)), asset.dimensions, true);
|
||||
if (thumbnailImage != nil) {
|
||||
dict[@"previewImage"] = thumbnailImage;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (timer != nil)
|
||||
dict[@"timer"] = timer;
|
||||
else if (groupedId != nil && !hasAnyTimers)
|
||||
|
|
@ -872,10 +919,17 @@
|
|||
|
||||
UIImage *(^cropVideoThumbnail)(UIImage *, CGSize, CGSize, bool) = ^UIImage *(UIImage *image, CGSize targetSize, CGSize sourceSize, bool resize)
|
||||
{
|
||||
if ([adjustments cropAppliedForAvatar:false] || adjustments.hasPainting)
|
||||
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);
|
||||
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;
|
||||
}
|
||||
if (adjustments.toolsApplied) {
|
||||
image = [PGPhotoEditor resultImageForImage:image adjustments:adjustments];
|
||||
}
|
||||
return TGPhotoEditorCrop(image, paintingImage, adjustments.cropOrientation, 0, scaledCropRect, adjustments.cropMirrored, targetSize, sourceSize, resize);
|
||||
}
|
||||
|
||||
return image;
|
||||
|
|
@ -886,7 +940,7 @@
|
|||
CGSize imageSize = TGFillSize(asset.dimensions, CGSizeMake(384, 384));
|
||||
return [[TGMediaAssetImageSignals videoThumbnailForAVAsset:avAsset size:imageSize timestamp:CMTimeMakeWithSeconds(adjustments.trimStartValue, NSEC_PER_SEC)] map:^UIImage *(UIImage *image)
|
||||
{
|
||||
return cropVideoThumbnail(image, TGScaleToFill(asset.dimensions, CGSizeMake(256, 256)), asset.dimensions, true);
|
||||
return cropVideoThumbnail(image, TGScaleToFill(asset.dimensions, CGSizeMake(384, 384)), asset.dimensions, true);
|
||||
}];
|
||||
}];
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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];
|
||||
|
||||
|
|
@ -624,10 +653,21 @@
|
|||
|
||||
if (dataSuccess && dataOutUrl != NULL)
|
||||
*dataOutUrl = dataUrl;
|
||||
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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];
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -29,11 +29,15 @@
|
|||
#import "TGMediaPickerGalleryVideoScrubber.h"
|
||||
#import "TGMediaPickerScrubberHeaderView.h"
|
||||
|
||||
#import "TGPhotoEditorPreviewView.h"
|
||||
|
||||
#import <LegacyComponents/TGModernGalleryVideoView.h>
|
||||
#import "TGModernGalleryVideoContentView.h"
|
||||
|
||||
#import <LegacyComponents/TGMenuView.h>
|
||||
|
||||
#import "PGPhotoEditor.h"
|
||||
|
||||
@interface TGMediaPickerGalleryVideoItemView() <TGMediaPickerGalleryVideoScrubberDataSource, TGMediaPickerGalleryVideoScrubberDelegate>
|
||||
{
|
||||
UIView *_containerView;
|
||||
|
|
@ -65,7 +69,10 @@
|
|||
|
||||
UILabel *_fileInfoLabel;
|
||||
|
||||
TGModernGalleryVideoView *_videoView;
|
||||
// TGModernGalleryVideoView *_videoView;
|
||||
TGPhotoEditorPreviewView *_videoView;
|
||||
PGPhotoEditor *_photoEditor;
|
||||
|
||||
UIImageView *_paintingImageView;
|
||||
|
||||
NSTimer *_positionTimer;
|
||||
|
|
@ -148,10 +155,10 @@
|
|||
_curtainView.hidden = true;
|
||||
[_contentView addSubview:_curtainView];
|
||||
|
||||
_actionButton = [[TGModernButton alloc] initWithFrame:CGRectMake(0, 0, 50, 50)];
|
||||
_actionButton = [[TGModernButton alloc] initWithFrame:CGRectMake(0, 0, 60, 60)];
|
||||
_actionButton.modernHighlight = true;
|
||||
|
||||
CGFloat circleDiameter = 50.0f;
|
||||
CGFloat circleDiameter = 60.0f;
|
||||
static UIImage *highlightImage = nil;
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^
|
||||
|
|
@ -166,7 +173,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];
|
||||
|
|
@ -430,6 +438,8 @@
|
|||
|
||||
if (adjustments.sendAsGif || ([strongSelf itemIsLivePhoto]))
|
||||
[strongSelf setPlayButtonHidden:true animated:false];
|
||||
|
||||
[_photoEditor importAdjustments:adjustments];
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -864,7 +874,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};
|
||||
|
|
@ -972,19 +983,22 @@
|
|||
if (_videoView != nil)
|
||||
{
|
||||
SMetaDisposable *currentAudioSession = _currentAudioSession;
|
||||
if (currentAudioSession)
|
||||
{
|
||||
_videoView.deallocBlock = ^
|
||||
{
|
||||
[[SQueue concurrentDefaultQueue] dispatch:^
|
||||
{
|
||||
[currentAudioSession setDisposable:nil];
|
||||
}];
|
||||
};
|
||||
}
|
||||
[_videoView cleanupPlayer];
|
||||
// if (currentAudioSession)
|
||||
// {
|
||||
// _videoView.deallocBlock = ^
|
||||
// {
|
||||
// [[SQueue concurrentDefaultQueue] dispatch:^
|
||||
// {
|
||||
// [currentAudioSession setDisposable:nil];
|
||||
// }];
|
||||
// };
|
||||
// }
|
||||
// [_videoView cleanupPlayer];
|
||||
[_videoView removeFromSuperview];
|
||||
_videoView = nil;
|
||||
|
||||
[_photoEditor cleanup];
|
||||
_photoEditor = nil;
|
||||
}
|
||||
|
||||
self.isPlaying = false;
|
||||
|
|
@ -1041,15 +1055,26 @@
|
|||
|
||||
strongSelf->_didPlayToEndObserver = [[TGObserverProxy alloc] initWithTarget:strongSelf targetSelector:@selector(playerItemDidPlayToEndTime:) name:AVPlayerItemDidPlayToEndTimeNotification object:playerItem];
|
||||
|
||||
strongSelf->_videoView = [[TGModernGalleryVideoView alloc] initWithFrame:strongSelf->_playerView.bounds player:strongSelf->_player];
|
||||
strongSelf->_videoView.frame = strongSelf->_imageView.frame;
|
||||
strongSelf->_videoView.playerLayer.videoGravity = AVLayerVideoGravityResizeAspectFill;
|
||||
strongSelf->_videoView.playerLayer.opaque = false;
|
||||
strongSelf->_videoView.playerLayer.backgroundColor = nil;
|
||||
[strongSelf->_playerContainerView insertSubview:strongSelf->_videoView belowSubview:strongSelf->_paintingImageView];
|
||||
// strongSelf->_videoView = [[TGModernGalleryVideoView alloc] initWithFrame:strongSelf->_playerView.bounds player:strongSelf->_player];
|
||||
// strongSelf->_videoView.frame = strongSelf->_imageView.frame;
|
||||
// strongSelf->_videoView.playerLayer.videoGravity = AVLayerVideoGravityResizeAspectFill;
|
||||
// strongSelf->_videoView.playerLayer.opaque = false;
|
||||
// strongSelf->_videoView.playerLayer.backgroundColor = nil;
|
||||
// [strongSelf->_playerContainerView insertSubview:strongSelf->_videoView belowSubview:strongSelf->_paintingImageView];
|
||||
|
||||
TGVideoEditAdjustments *adjustments = (TGVideoEditAdjustments *)[strongSelf.item.editingContext adjustmentsForItem:strongSelf.item.editableMediaItem];
|
||||
|
||||
strongSelf->_videoView = [[TGPhotoEditorPreviewView alloc] initWithFrame:strongSelf->_imageView.frame];
|
||||
[strongSelf->_playerContainerView insertSubview:strongSelf->_videoView belowSubview:strongSelf->_paintingImageView];
|
||||
|
||||
[strongSelf->_videoView setNeedsTransitionIn];
|
||||
[strongSelf->_videoView performTransitionInIfNeeded];
|
||||
|
||||
strongSelf->_photoEditor = [[PGPhotoEditor alloc] initWithOriginalSize:_videoDimensions adjustments:adjustments forVideo:true enableStickers:true];
|
||||
strongSelf->_photoEditor.previewOutput = strongSelf->_videoView;
|
||||
[strongSelf->_photoEditor setPlayerItem:playerItem];
|
||||
[strongSelf->_photoEditor processAnimated:false completion:nil];
|
||||
|
||||
[strongSelf _seekToPosition:adjustments.trimStartValue manual:false];
|
||||
if (adjustments.trimEndValue > DBL_EPSILON)
|
||||
[strongSelf updatePlayerRange:adjustments.trimEndValue];
|
||||
|
|
@ -1440,6 +1465,8 @@
|
|||
return;
|
||||
|
||||
AVAsset *avAsset = self.item.avAsset ?: _player.currentItem.asset;
|
||||
TGMediaEditingContext *editingContext = self.item.editingContext;
|
||||
id<TGMediaEditableItem> editableItem = self.item.editableMediaItem;
|
||||
|
||||
SSignal *thumbnailsSignal = nil;
|
||||
if ([self.item.asset isKindOfClass:[TGMediaAsset class]] && ![self itemIsLivePhoto])
|
||||
|
|
@ -1450,7 +1477,26 @@
|
|||
_requestingThumbnails = true;
|
||||
|
||||
__weak TGMediaPickerGalleryVideoItemView *weakSelf = self;
|
||||
[_thumbnailsDisposable setDisposable:[[thumbnailsSignal deliverOn:[SQueue mainQueue]] startWithNext:^(NSArray *images)
|
||||
[_thumbnailsDisposable setDisposable:[[[thumbnailsSignal map:^NSArray *(NSArray *images) {
|
||||
id<TGMediaEditAdjustments> adjustments = [editingContext adjustmentsForItem:editableItem];
|
||||
if (adjustments.toolsApplied) {
|
||||
NSMutableArray *editedImages = [[NSMutableArray alloc] init];
|
||||
PGPhotoEditor *editor = [[PGPhotoEditor alloc] initWithOriginalSize:adjustments.originalSize adjustments:adjustments forVideo:false enableStickers:true];
|
||||
editor.standalone = true;
|
||||
for (UIImage *image in images) {
|
||||
[editor setImage:image forCropRect:adjustments.cropRect cropRotation:0.0 cropOrientation:adjustments.cropOrientation cropMirrored:adjustments.cropMirrored fullSize:false];
|
||||
UIImage *resultImage = editor.currentResultImage;
|
||||
if (resultImage != nil) {
|
||||
[editedImages addObject:resultImage];
|
||||
} else {
|
||||
[editedImages addObject:image];
|
||||
}
|
||||
}
|
||||
return editedImages;
|
||||
} else {
|
||||
return images;
|
||||
}
|
||||
}] deliverOn:[SQueue mainQueue]] startWithNext:^(NSArray *images)
|
||||
{
|
||||
__strong TGMediaPickerGalleryVideoItemView *strongSelf = weakSelf;
|
||||
if (strongSelf == nil)
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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 ()
|
||||
|
||||
|
|
@ -37,6 +42,7 @@
|
|||
@property (nonatomic, readonly) bool succeed;
|
||||
|
||||
- (instancetype)initWithAssetReaderOutput:(AVAssetReaderOutput *)assetReaderOutput assetWriterInput:(AVAssetWriterInput *)assetWriterInput;
|
||||
- (instancetype)initWithUIImage:(UIImage *)image duration:(NSTimeInterval)duration assetWriterInput:(AVAssetWriterInput *)assetWriterInput;
|
||||
|
||||
- (void)startWithTimeRange:(CMTimeRange)timeRange progressBlock:(void (^)(CGFloat progress))progressBlock completionBlock:(void (^)(void))completionBlock;
|
||||
- (void)cancel;
|
||||
|
|
@ -68,6 +74,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 +87,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 +101,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 +154,7 @@
|
|||
}
|
||||
}
|
||||
|
||||
if (![self setupAssetReaderWriterForAVAsset:avAsset outputURL:outputUrl preset:preset adjustments:adjustments inhibitAudio:inhibitAudio conversionContext:context error:&error])
|
||||
if (![self setupAssetReaderWriterForAVAsset:avAsset image:nil outputURL:outputUrl preset:preset entityRenderer:entityRenderer adjustments:adjustments inhibitAudio:inhibitAudio conversionContext:context error:&error])
|
||||
{
|
||||
[subscriber putError:error];
|
||||
return;
|
||||
|
|
@ -204,6 +212,99 @@
|
|||
}];
|
||||
}
|
||||
|
||||
+ (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];
|
||||
|
||||
NSString *path = TGComponentsPathForResource(@"blank_1080p", @"mp4");
|
||||
AVAsset *avAsset = [[AVURLAsset alloc] initWithURL:[NSURL fileURLWithPath:path] options:nil];
|
||||
|
||||
NSArray *requiredKeys = @[ @"tracks", @"duration", @"playable" ];
|
||||
[avAsset loadValuesAsynchronouslyForKeys:requiredKeys completionHandler:^
|
||||
{
|
||||
[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 setupAssetReaderWriterForAVAsset:avAsset image: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 +322,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 image:(UIImage *)image 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);
|
||||
|
|
@ -232,6 +333,8 @@
|
|||
CGRect cropRect = hasCropping ? CGRectIntegral(adjustments.cropRect) : transformedRect;
|
||||
if (cropRect.size.width < FLT_EPSILON || cropRect.size.height < FLT_EPSILON)
|
||||
cropRect = transformedRect;
|
||||
if (image != nil)
|
||||
cropRect = CGRectMake(0.0f, 0.0f, image.size.width, image.size.height);
|
||||
|
||||
CGSize maxDimensions = [TGMediaVideoConversionPresetSettings maximumSizeForPreset:preset];
|
||||
CGSize outputDimensions = TGFitSizeF(cropRect.size, maxDimensions);
|
||||
|
|
@ -240,8 +343,93 @@
|
|||
|
||||
if (TGOrientationIsSideward(adjustments.cropOrientation, NULL))
|
||||
outputDimensions = CGSizeMake(outputDimensions.height, outputDimensions.width);
|
||||
|
||||
AVMutableCompositionTrack *trimVideoTrack = [composition addMutableTrackWithMediaType:AVMediaTypeVideo preferredTrackID:kCMPersistentTrackID_Invalid];
|
||||
[trimVideoTrack insertTimeRange:timeRange ofTrack:videoTrack atTime:kCMTimeZero error:NULL];
|
||||
|
||||
AVMutableVideoComposition *videoComposition = [AVMutableVideoComposition videoComposition];
|
||||
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];
|
||||
editor.standalone = true;
|
||||
ciContext = [CIContext contextWithEAGLContext:[[GPUImageContext sharedImageProcessingContext] context]];
|
||||
}
|
||||
|
||||
CIImage *backgroundCIImage = nil;
|
||||
if (image != nil) {
|
||||
backgroundCIImage = [[CIImage alloc] initWithImage:image];
|
||||
}
|
||||
|
||||
__block CIImage *overlayCIImage = nil;
|
||||
videoComposition = [AVMutableVideoComposition videoCompositionWithAsset:avAsset applyingCIFiltersWithHandler:^(AVAsynchronousCIImageFilteringRequest * _Nonnull request) {
|
||||
__block CIImage *resultImage = request.sourceImage;
|
||||
|
||||
if (backgroundCIImage != nil) {
|
||||
resultImage = backgroundCIImage;
|
||||
}
|
||||
|
||||
CGSize size = resultImage.extent.size;
|
||||
|
||||
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 = size.width / overlayCIImage.extent.size.width;
|
||||
overlayCIImage = [overlayCIImage imageByApplyingTransform:CGAffineTransformMakeScale(scale, scale)];
|
||||
}
|
||||
resultImage = [overlayCIImage imageByCompositingOverImage:resultImage];
|
||||
}
|
||||
|
||||
if (entityRenderer != nil) {
|
||||
[entityRenderer entitiesForTime:request.compositionTime size: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)
|
||||
|
|
@ -255,63 +443,45 @@
|
|||
if (!CMTIME_IS_VALID(videoComposition.frameDuration))
|
||||
videoComposition.frameDuration = CMTimeMake(1, 30);
|
||||
|
||||
if (image != nil)
|
||||
videoComposition.frameDuration = CMTimeMake(1, 30);
|
||||
|
||||
videoComposition.renderSize = [self _renderSizeWithCropSize:cropRect.size rotateSideward:TGOrientationIsSideward(adjustments.cropOrientation, NULL)];
|
||||
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);
|
||||
|
||||
|
||||
CALayer *videoLayer = [CALayer layer];
|
||||
videoLayer.frame = parentLayer.frame;
|
||||
[parentLayer addSublayer:videoLayer];
|
||||
|
||||
|
||||
CGSize parentSize = parentLayer.bounds.size;
|
||||
if (TGOrientationIsSideward(adjustments.cropOrientation, NULL))
|
||||
parentSize = CGSizeMake(parentSize.height, parentSize.width);
|
||||
|
||||
|
||||
CGSize size = CGSizeMake(parentSize.width * transformedSize.width / cropRect.size.width, parentSize.height * transformedSize.height / cropRect.size.height);
|
||||
CGPoint origin = CGPointMake(-parentSize.width / cropRect.size.width * cropRect.origin.x, -parentSize.height / cropRect.size.height * (transformedSize.height - cropRect.size.height - cropRect.origin.y));
|
||||
|
||||
|
||||
CALayer *rotationLayer = [CALayer layer];
|
||||
rotationLayer.frame = CGRectMake(0, 0, parentSize.width, parentSize.height);
|
||||
[parentLayer addSublayer:rotationLayer];
|
||||
|
||||
|
||||
UIImageOrientation orientation = TGMirrorSidewardOrientation(adjustments.cropOrientation);
|
||||
CATransform3D layerTransform = CATransform3DMakeTranslation(rotationLayer.frame.size.width / 2.0f, rotationLayer.frame.size.height / 2.0f, 0.0f);
|
||||
layerTransform = CATransform3DRotate(layerTransform, TGRotationForOrientation(orientation), 0.0f, 0.0f, 1.0f);
|
||||
layerTransform = CATransform3DTranslate(layerTransform, -parentLayer.bounds.size.width / 2.0f, -parentLayer.bounds.size.height / 2.0f, 0.0f);
|
||||
rotationLayer.transform = layerTransform;
|
||||
rotationLayer.frame = parentLayer.frame;
|
||||
|
||||
|
||||
CALayer *overlayLayer = [CALayer layer];
|
||||
overlayLayer.contents = (id)overlayImage.CGImage;
|
||||
overlayLayer.frame = CGRectMake(origin.x, origin.y, size.width, size.height);
|
||||
[rotationLayer addSublayer:overlayLayer];
|
||||
|
||||
|
||||
videoComposition.animationTool = [AVVideoCompositionCoreAnimationTool videoCompositionCoreAnimationToolWithPostProcessingAsVideoLayer:videoLayer inLayer:parentLayer];
|
||||
}
|
||||
|
||||
|
|
@ -335,83 +505,122 @@
|
|||
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)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
|
||||
{
|
||||
TGMediaSampleBufferProcessor *videoProcessor = nil;
|
||||
TGMediaSampleBufferProcessor *audioProcessor = nil;
|
||||
|
||||
AVAssetTrack *audioTrack = [[avAsset tracksWithMediaType:AVMediaTypeAudio] firstObject];
|
||||
AVAssetTrack *videoTrack = [[avAsset tracksWithMediaType:AVMediaTypeVideo] firstObject];
|
||||
if (videoTrack == nil)
|
||||
return false;
|
||||
|
||||
CGSize dimensions = CGSizeZero;
|
||||
CMTimeRange timeRange = videoTrack.timeRange;
|
||||
if (adjustments.trimApplied)
|
||||
{
|
||||
NSTimeInterval duration = CMTimeGetSeconds(videoTrack.timeRange.duration);
|
||||
if (adjustments.trimEndValue < duration)
|
||||
{
|
||||
timeRange = adjustments.trimTimeRange;
|
||||
}
|
||||
else
|
||||
{
|
||||
timeRange = CMTimeRangeMake(CMTimeMakeWithSeconds(adjustments.trimStartValue, NSEC_PER_SEC), CMTimeMakeWithSeconds(duration - adjustments.trimStartValue, NSEC_PER_SEC));
|
||||
}
|
||||
}
|
||||
timeRange = CMTimeRangeMake(CMTimeAdd(timeRange.start, CMTimeMake(10, 100)), CMTimeSubtract(timeRange.duration, CMTimeMake(10, 100)));
|
||||
|
||||
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];
|
||||
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];
|
||||
|
||||
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];
|
||||
|
||||
if (!inhibitAudio && [TGMediaVideoConversionPresetSettings keepAudioForPreset:preset] && audioTrack != nil)
|
||||
{
|
||||
AVMutableCompositionTrack *trimAudioTrack = [composition addMutableTrackWithMediaType:AVMediaTypeAudio preferredTrackID:kCMPersistentTrackID_Invalid];
|
||||
[trimAudioTrack insertTimeRange:timeRange ofTrack:audioTrack atTime:kCMTimeZero error:NULL];
|
||||
if (trimAudioTrack == nil)
|
||||
if (image == nil) {
|
||||
TGMediaSampleBufferProcessor *videoProcessor = nil;
|
||||
TGMediaSampleBufferProcessor *audioProcessor = nil;
|
||||
|
||||
AVAssetTrack *audioTrack = [[avAsset tracksWithMediaType:AVMediaTypeAudio] firstObject];
|
||||
AVAssetTrack *videoTrack = [[avAsset tracksWithMediaType:AVMediaTypeVideo] firstObject];
|
||||
if (videoTrack == nil)
|
||||
return false;
|
||||
|
||||
CGSize dimensions = CGSizeZero;
|
||||
CMTimeRange timeRange = videoTrack.timeRange;
|
||||
if (adjustments.trimApplied)
|
||||
{
|
||||
NSTimeInterval duration = CMTimeGetSeconds(videoTrack.timeRange.duration);
|
||||
if (adjustments.trimEndValue < duration)
|
||||
{
|
||||
timeRange = adjustments.trimTimeRange;
|
||||
}
|
||||
else
|
||||
{
|
||||
timeRange = CMTimeRangeMake(CMTimeMakeWithSeconds(adjustments.trimStartValue, NSEC_PER_SEC), CMTimeMakeWithSeconds(duration - adjustments.trimStartValue, NSEC_PER_SEC));
|
||||
}
|
||||
}
|
||||
timeRange = CMTimeRangeMake(CMTimeAdd(timeRange.start, CMTimeMake(10, 100)), CMTimeSubtract(timeRange.duration, CMTimeMake(10, 100)));
|
||||
|
||||
NSDictionary *outputSettings = nil;
|
||||
AVMutableComposition *composition = [AVMutableComposition composition];
|
||||
AVAssetReaderVideoCompositionOutput *output = [self setupVideoCompositionOutputWithAVAsset:avAsset image:nil 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;
|
||||
|
||||
AVAssetReaderOutput *output = [AVAssetReaderTrackOutput assetReaderTrackOutputWithTrack:trimAudioTrack outputSettings:@{ AVFormatIDKey: @(kAudioFormatLinearPCM) }];
|
||||
[assetReader addOutput:output];
|
||||
|
||||
AVAssetWriterInput *input = [AVAssetWriterInput assetWriterInputWithMediaType:AVMediaTypeAudio outputSettings:[TGMediaVideoConversionPresetSettings audioSettingsForPreset:preset]];
|
||||
AVAssetWriterInput *input = [AVAssetWriterInput assetWriterInputWithMediaType:AVMediaTypeVideo outputSettings:outputSettings];
|
||||
[assetWriter addInput:input];
|
||||
|
||||
audioProcessor = [[TGMediaSampleBufferProcessor alloc] initWithAssetReaderOutput:output assetWriterInput:input];
|
||||
videoProcessor = [[TGMediaSampleBufferProcessor alloc] initWithAssetReaderOutput:output assetWriterInput:input];
|
||||
|
||||
if (!inhibitAudio && [TGMediaVideoConversionPresetSettings keepAudioForPreset:preset] && audioTrack != nil)
|
||||
{
|
||||
AVMutableCompositionTrack *trimAudioTrack = [composition addMutableTrackWithMediaType:AVMediaTypeAudio preferredTrackID:kCMPersistentTrackID_Invalid];
|
||||
[trimAudioTrack insertTimeRange:timeRange ofTrack:audioTrack atTime:kCMTimeZero error:NULL];
|
||||
if (trimAudioTrack == nil)
|
||||
return false;
|
||||
|
||||
AVAssetReaderOutput *output = [AVAssetReaderTrackOutput assetReaderTrackOutputWithTrack:trimAudioTrack outputSettings:@{ AVFormatIDKey: @(kAudioFormatLinearPCM) }];
|
||||
[assetReader addOutput:output];
|
||||
|
||||
AVAssetWriterInput *input = [AVAssetWriterInput assetWriterInputWithMediaType:AVMediaTypeAudio outputSettings:[TGMediaVideoConversionPresetSettings audioSettingsForPreset:preset]];
|
||||
[assetWriter addInput:input];
|
||||
|
||||
audioProcessor = [[TGMediaSampleBufferProcessor alloc] initWithAssetReaderOutput:output assetWriterInput:input];
|
||||
}
|
||||
|
||||
[outConversionContext modify:^id(TGMediaVideoConversionContext *currentContext)
|
||||
{
|
||||
return [currentContext contextWithAssetReader:assetReader assetWriter:assetWriter videoProcessor:videoProcessor audioProcessor:audioProcessor timeRange:timeRange dimensions:dimensions entityRenderer:entityRenderer];
|
||||
}];
|
||||
|
||||
return true;
|
||||
} else {
|
||||
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 = [[avAsset tracksWithMediaType:AVMediaTypeVideo] firstObject];
|
||||
if (videoTrack == nil)
|
||||
return false;
|
||||
|
||||
AVMutableCompositionTrack *mutableCompositionVideoTrack = [composition addMutableTrackWithMediaType:AVMediaTypeVideo preferredTrackID:kCMPersistentTrackID_Invalid];
|
||||
[mutableCompositionVideoTrack insertTimeRange:timeRange ofTrack:videoTrack atTime:kCMTimeZero error:nil];
|
||||
|
||||
AVMutableComposition *mock = [AVMutableComposition composition];
|
||||
AVMutableCompositionTrack *mockTrack = [mock addMutableTrackWithMediaType:AVMediaTypeVideo preferredTrackID:kCMPersistentTrackID_Invalid];
|
||||
[mockTrack insertTimeRange:timeRange ofTrack:videoTrack atTime:kCMTimeZero error:nil];
|
||||
|
||||
AVAssetReaderVideoCompositionOutput *output = [self setupVideoCompositionOutputWithAVAsset:mock image:image 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;
|
||||
}
|
||||
|
||||
[outConversionContext modify:^id(TGMediaVideoConversionContext *currentContext)
|
||||
{
|
||||
return [currentContext contextWithAssetReader:assetReader assetWriter:assetWriter videoProcessor:videoProcessor audioProcessor:audioProcessor timeRange:timeRange dimensions:dimensions];
|
||||
}];
|
||||
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
+ (void)processWithConversionContext:(SAtomic *)context_ completionBlock:(void (^)(void))completionBlock
|
||||
|
|
@ -865,6 +1074,7 @@ static CGFloat progressOfSampleBufferInTimeRange(CMSampleBufferRef sampleBuffer,
|
|||
context->_dimensions = _dimensions;
|
||||
context->_coverImage = _coverImage;
|
||||
context->_imageGenerator = _imageGenerator;
|
||||
context->_entityRenderer = _entityRenderer;
|
||||
return context;
|
||||
}
|
||||
|
||||
|
|
@ -883,6 +1093,7 @@ static CGFloat progressOfSampleBufferInTimeRange(CMSampleBufferRef sampleBuffer,
|
|||
context->_dimensions = _dimensions;
|
||||
context->_coverImage = _coverImage;
|
||||
context->_imageGenerator = _imageGenerator;
|
||||
context->_entityRenderer = _entityRenderer;
|
||||
return context;
|
||||
}
|
||||
|
||||
|
|
@ -900,6 +1111,7 @@ static CGFloat progressOfSampleBufferInTimeRange(CMSampleBufferRef sampleBuffer,
|
|||
context->_dimensions = _dimensions;
|
||||
context->_coverImage = _coverImage;
|
||||
context->_imageGenerator = imageGenerator;
|
||||
context->_entityRenderer = _entityRenderer;
|
||||
return context;
|
||||
}
|
||||
|
||||
|
|
@ -917,10 +1129,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 +1147,7 @@ static CGFloat progressOfSampleBufferInTimeRange(CMSampleBufferRef sampleBuffer,
|
|||
context->_dimensions = dimensions;
|
||||
context->_coverImage = _coverImage;
|
||||
context->_imageGenerator = _imageGenerator;
|
||||
context->_entityRenderer = entityRenderer;
|
||||
return context;
|
||||
}
|
||||
|
||||
|
|
@ -995,9 +1209,8 @@ static CGFloat progressOfSampleBufferInTimeRange(CMSampleBufferRef sampleBuffer,
|
|||
{
|
||||
return (CGSize){ 240.0f, 240.0f };
|
||||
}
|
||||
|
||||
default:
|
||||
return (CGSize){ 640.0f, 640.0f };
|
||||
return (CGSize){ 848.0f, 848.0f };
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1043,11 +1256,7 @@ static CGFloat progressOfSampleBufferInTimeRange(CMSampleBufferRef sampleBuffer,
|
|||
|
||||
NSDictionary *codecSettings = @
|
||||
{
|
||||
#if DEBUG
|
||||
AVVideoAverageBitRateKey: @([self _videoBitrateKbpsForPreset:preset] * 500),
|
||||
#else
|
||||
AVVideoAverageBitRateKey: @([self _videoBitrateKbpsForPreset:preset] * 1000),
|
||||
#endif
|
||||
AVVideoCleanApertureKey: videoCleanApertureSettings,
|
||||
AVVideoPixelAspectRatioKey: videoAspectRatioSettings
|
||||
};
|
||||
|
|
@ -1084,7 +1293,7 @@ static CGFloat progressOfSampleBufferInTimeRange(CMSampleBufferRef sampleBuffer,
|
|||
return 300;
|
||||
|
||||
default:
|
||||
return 700;
|
||||
return 500;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue