Improve smaller text rendering

This commit is contained in:
Ilya Laktyushin 2023-07-23 04:36:11 +02:00
parent a196a1684b
commit 8eaee14c41
10 changed files with 171 additions and 339 deletions

View File

@ -35,6 +35,16 @@ public struct LayoutMetrics: Equatable {
}
}
public extension LayoutMetrics {
var isTablet: Bool {
if case .regular = self.widthClass {
return true
} else {
return false
}
}
}
public enum LayoutOrientation {
case portrait
case landscape

View File

@ -693,7 +693,7 @@ public final class DrawingTextEntityView: DrawingEntityView, UITextViewDelegate
func getRenderImage() -> UIImage? {
let rect = self.bounds
UIGraphicsBeginImageContextWithOptions(rect.size, false, 2.0)
UIGraphicsBeginImageContextWithOptions(rect.size, false, 3.0)
self.textView.drawHierarchy(in: rect, afterScreenUpdates: true)
let image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()

View File

@ -805,154 +805,3 @@ public final class MediaEditor {
}
}
}
final class MediaEditorRenderChain {
fileprivate let enhancePass = EnhanceRenderPass()
fileprivate let sharpenPass = SharpenRenderPass()
fileprivate let blurPass = BlurRenderPass()
fileprivate let adjustmentsPass = AdjustmentsRenderPass()
var renderPasses: [RenderPass] {
return [
self.enhancePass,
self.sharpenPass,
self.blurPass,
self.adjustmentsPass
]
}
func update(values: MediaEditorValues) {
for key in EditorToolKey.allCases {
let value = values.toolValues[key]
switch key {
case .enhance:
if let value = value as? Float {
self.enhancePass.value = abs(value)
} else {
self.enhancePass.value = 0.0
}
case .brightness:
if let value = value as? Float {
self.adjustmentsPass.adjustments.exposure = value
} else {
self.adjustmentsPass.adjustments.exposure = 0.0
}
case .contrast:
if let value = value as? Float {
self.adjustmentsPass.adjustments.contrast = value
} else {
self.adjustmentsPass.adjustments.contrast = 0.0
}
case .saturation:
if let value = value as? Float {
self.adjustmentsPass.adjustments.saturation = value
} else {
self.adjustmentsPass.adjustments.saturation = 0.0
}
case .warmth:
if let value = value as? Float {
self.adjustmentsPass.adjustments.warmth = value
} else {
self.adjustmentsPass.adjustments.warmth = 0.0
}
case .fade:
if let value = value as? Float {
self.adjustmentsPass.adjustments.fade = value
} else {
self.adjustmentsPass.adjustments.fade = 0.0
}
case .highlights:
if let value = value as? Float {
self.adjustmentsPass.adjustments.highlights = value
} else {
self.adjustmentsPass.adjustments.highlights = 0.0
}
case .shadows:
if let value = value as? Float {
self.adjustmentsPass.adjustments.shadows = value
} else {
self.adjustmentsPass.adjustments.shadows = 0.0
}
case .vignette:
if let value = value as? Float {
self.adjustmentsPass.adjustments.vignette = value
} else {
self.adjustmentsPass.adjustments.vignette = 0.0
}
case .grain:
if let value = value as? Float {
self.adjustmentsPass.adjustments.grain = value
} else {
self.adjustmentsPass.adjustments.grain = 0.0
}
case .sharpen:
if let value = value as? Float {
self.sharpenPass.value = value
} else {
self.sharpenPass.value = 0.0
}
case .shadowsTint:
if let value = value as? TintValue {
if value.color != .clear {
let (red, green, blue, _) = value.color.components
self.adjustmentsPass.adjustments.shadowsTintColor = simd_float3(Float(red), Float(green), Float(blue))
self.adjustmentsPass.adjustments.shadowsTintIntensity = value.intensity
} else {
self.adjustmentsPass.adjustments.shadowsTintIntensity = 0.0
}
}
case .highlightsTint:
if let value = value as? TintValue {
if value.color != .clear {
let (red, green, blue, _) = value.color.components
self.adjustmentsPass.adjustments.shadowsTintColor = simd_float3(Float(red), Float(green), Float(blue))
self.adjustmentsPass.adjustments.highlightsTintIntensity = value.intensity
} else {
self.adjustmentsPass.adjustments.highlightsTintIntensity = 0.0
}
}
case .blur:
if let value = value as? BlurValue {
switch value.mode {
case .off:
self.blurPass.mode = .off
case .linear:
self.blurPass.mode = .linear
case .radial:
self.blurPass.mode = .radial
case .portrait:
self.blurPass.mode = .portrait
}
self.blurPass.intensity = value.intensity
self.blurPass.value.size = Float(value.size)
self.blurPass.value.position = simd_float2(Float(value.position.x), Float(value.position.y))
self.blurPass.value.falloff = Float(value.falloff)
self.blurPass.value.rotation = Float(value.rotation)
}
case .curves:
if var value = value as? CurvesValue {
let allDataPoints = value.all.dataPoints
let redDataPoints = value.red.dataPoints
let greenDataPoints = value.green.dataPoints
let blueDataPoints = value.blue.dataPoints
self.adjustmentsPass.adjustments.hasCurves = 1.0
self.adjustmentsPass.allCurve = allDataPoints
self.adjustmentsPass.redCurve = redDataPoints
self.adjustmentsPass.greenCurve = greenDataPoints
self.adjustmentsPass.blueCurve = blueDataPoints
} else {
self.adjustmentsPass.adjustments.hasCurves = 0.0
}
}
}
}
}
public func debugSaveImage(_ image: UIImage, name: String) {
let path = NSTemporaryDirectory() + "debug_\(name)_\(Int64.random(in: .min ... .max)).png"
print(path)
if let data = image.pngData() {
try? data.write(to: URL(fileURLWithPath: path))
}
}

View File

@ -115,7 +115,6 @@ final class MediaEditorComposer {
var pixelBuffer: CVPixelBuffer?
CVPixelBufferPoolCreatePixelBuffer(kCFAllocatorDefault, pool, &pixelBuffer)
if let pixelBuffer {
processImage(inputImage: ciImage, time: time, completion: { compositedImage in
if var compositedImage {

View File

@ -41,9 +41,9 @@ private func prerenderTextTransformations(entity: DrawingTextEntity, image: UIIm
if let cgImage = image.cgImage {
context.draw(cgImage, in: drawRect)
}
})!
}, scale: 1.0)!
return MediaEditorComposerStaticEntity(image: CIImage(image: newImage, options: [.colorSpace: colorSpace])!, position: entity.position, scale: 1.0, rotation: 0.0, baseSize: nil, baseScale: 0.333, mirrored: false)
return MediaEditorComposerStaticEntity(image: CIImage(image: newImage, options: [.colorSpace: colorSpace])!, position: entity.position, scale: 1.0, rotation: 0.0, baseSize: nil, baseScale: 1.0, mirrored: false)
}
func composerEntitiesForDrawingEntity(account: Account, entity: DrawingEntity, colorSpace: CGColorSpace, tintColor: UIColor? = nil) -> [MediaEditorComposerEntity] {
@ -69,9 +69,9 @@ func composerEntitiesForDrawingEntity(account: Account, entity: DrawingEntity, c
return [MediaEditorComposerStaticEntity(image: image, position: CGPoint(x: entity.drawingSize.width * 0.5, y: entity.drawingSize.height * 0.5), scale: 1.0, rotation: 0.0, baseSize: entity.drawingSize, baseScale: nil, mirrored: false)]
} else if let entity = entity as? DrawingTextEntity {
var entities: [MediaEditorComposerEntity] = []
// entities.append(prerenderTextTransformations(entity: entity, image: renderImage, colorSpace: colorSpace))
entities.append(prerenderTextTransformations(entity: entity, image: renderImage, colorSpace: colorSpace))
entities.append(MediaEditorComposerStaticEntity(image: image, position: entity.position, scale: entity.scale, rotation: entity.rotation, baseSize: nil, baseScale: 0.5, mirrored: false))
// entities.append(MediaEditorComposerStaticEntity(image: image, position: entity.position, scale: entity.scale, rotation: entity.rotation, baseSize: nil, baseScale: 0.5, mirrored: false))
if let renderSubEntities = entity.renderSubEntities {
for subEntity in renderSubEntities {
entities.append(contentsOf: composerEntitiesForDrawingEntity(account: account, entity: subEntity, colorSpace: colorSpace, tintColor: entity.color.toUIColor()))

View File

@ -0,0 +1,145 @@
import Foundation
import simd
final class MediaEditorRenderChain {
let enhancePass = EnhanceRenderPass()
let sharpenPass = SharpenRenderPass()
let blurPass = BlurRenderPass()
let adjustmentsPass = AdjustmentsRenderPass()
var renderPasses: [RenderPass] {
return [
self.enhancePass,
self.sharpenPass,
self.blurPass,
self.adjustmentsPass
]
}
func update(values: MediaEditorValues) {
for key in EditorToolKey.allCases {
let value = values.toolValues[key]
switch key {
case .enhance:
if let value = value as? Float {
self.enhancePass.value = abs(value)
} else {
self.enhancePass.value = 0.0
}
case .brightness:
if let value = value as? Float {
self.adjustmentsPass.adjustments.exposure = value
} else {
self.adjustmentsPass.adjustments.exposure = 0.0
}
case .contrast:
if let value = value as? Float {
self.adjustmentsPass.adjustments.contrast = value
} else {
self.adjustmentsPass.adjustments.contrast = 0.0
}
case .saturation:
if let value = value as? Float {
self.adjustmentsPass.adjustments.saturation = value
} else {
self.adjustmentsPass.adjustments.saturation = 0.0
}
case .warmth:
if let value = value as? Float {
self.adjustmentsPass.adjustments.warmth = value
} else {
self.adjustmentsPass.adjustments.warmth = 0.0
}
case .fade:
if let value = value as? Float {
self.adjustmentsPass.adjustments.fade = value
} else {
self.adjustmentsPass.adjustments.fade = 0.0
}
case .highlights:
if let value = value as? Float {
self.adjustmentsPass.adjustments.highlights = value
} else {
self.adjustmentsPass.adjustments.highlights = 0.0
}
case .shadows:
if let value = value as? Float {
self.adjustmentsPass.adjustments.shadows = value
} else {
self.adjustmentsPass.adjustments.shadows = 0.0
}
case .vignette:
if let value = value as? Float {
self.adjustmentsPass.adjustments.vignette = value
} else {
self.adjustmentsPass.adjustments.vignette = 0.0
}
case .grain:
if let value = value as? Float {
self.adjustmentsPass.adjustments.grain = value
} else {
self.adjustmentsPass.adjustments.grain = 0.0
}
case .sharpen:
if let value = value as? Float {
self.sharpenPass.value = value
} else {
self.sharpenPass.value = 0.0
}
case .shadowsTint:
if let value = value as? TintValue {
if value.color != .clear {
let (red, green, blue, _) = value.color.components
self.adjustmentsPass.adjustments.shadowsTintColor = simd_float3(Float(red), Float(green), Float(blue))
self.adjustmentsPass.adjustments.shadowsTintIntensity = value.intensity
} else {
self.adjustmentsPass.adjustments.shadowsTintIntensity = 0.0
}
}
case .highlightsTint:
if let value = value as? TintValue {
if value.color != .clear {
let (red, green, blue, _) = value.color.components
self.adjustmentsPass.adjustments.shadowsTintColor = simd_float3(Float(red), Float(green), Float(blue))
self.adjustmentsPass.adjustments.highlightsTintIntensity = value.intensity
} else {
self.adjustmentsPass.adjustments.highlightsTintIntensity = 0.0
}
}
case .blur:
if let value = value as? BlurValue {
switch value.mode {
case .off:
self.blurPass.mode = .off
case .linear:
self.blurPass.mode = .linear
case .radial:
self.blurPass.mode = .radial
case .portrait:
self.blurPass.mode = .portrait
}
self.blurPass.intensity = value.intensity
self.blurPass.value.size = Float(value.size)
self.blurPass.value.position = simd_float2(Float(value.position.x), Float(value.position.y))
self.blurPass.value.falloff = Float(value.falloff)
self.blurPass.value.rotation = Float(value.rotation)
}
case .curves:
if var value = value as? CurvesValue {
let allDataPoints = value.all.dataPoints
let redDataPoints = value.red.dataPoints
let greenDataPoints = value.green.dataPoints
let blueDataPoints = value.blue.dataPoints
self.adjustmentsPass.adjustments.hasCurves = 1.0
self.adjustmentsPass.allCurve = allDataPoints
self.adjustmentsPass.redCurve = redDataPoints
self.adjustmentsPass.greenCurve = greenDataPoints
self.adjustmentsPass.blueCurve = blueDataPoints
} else {
self.adjustmentsPass.adjustments.hasCurves = 0.0
}
}
}
}
}

View File

@ -35,8 +35,8 @@ swift_library(
"//submodules/TelegramUI/Components/TextFieldComponent",
"//submodules/TelegramUI/Components/ChatInputNode",
"//submodules/TelegramUI/Components/ChatEntityKeyboardInputNode",
"//submodules/TelegramUI/Components/PlainButtonComponent",
"//submodules/TooltipUI",
"//submodules/Components/BlurredBackgroundComponent",
"//submodules/AvatarNode",
"//submodules/TelegramUI/Components/ShareWithPeersScreen",
"//submodules/TelegramUI/Components/CameraButtonComponent",

View File

@ -19,7 +19,7 @@ import MessageInputPanelComponent
import TextFieldComponent
import EntityKeyboard
import TooltipUI
import BlurredBackgroundComponent
import PlainButtonComponent
import AvatarNode
import ShareWithPeersScreen
import PresentationDataUtils
@ -38,7 +38,6 @@ enum DrawingScreenType {
case sticker
}
private let privacyButtonTag = GenericComponentViewTag()
private let muteButtonTag = GenericComponentViewTag()
private let saveButtonTag = GenericComponentViewTag()
@ -237,11 +236,9 @@ final class MediaEditorScreenComponent: Component {
private let scrubber = ComponentView<Empty>()
private let privacyButton = ComponentView<Empty>()
private let flipStickerButton = ComponentView<Empty>()
private let muteButton = ComponentView<Empty>()
private let saveButton = ComponentView<Empty>()
private let settingsButton = ComponentView<Empty>()
private let textCancelButton = ComponentView<Empty>()
private let textDoneButton = ComponentView<Empty>()
@ -469,16 +466,6 @@ final class MediaEditorScreenComponent: Component {
view.layer.animateScale(from: 0.1, to: 1.0, duration: 0.2)
}
if let view = self.settingsButton.view {
view.layer.animateAlpha(from: 0.0, to: view.alpha, duration: 0.2)
view.layer.animateScale(from: 0.1, to: 1.0, duration: 0.2)
}
if let view = self.privacyButton.view {
view.layer.animateAlpha(from: 0.0, to: view.alpha, duration: 0.2)
view.layer.animateScale(from: 0.1, to: 1.0, duration: 0.2)
}
if let view = self.inputPanel.view {
view.layer.animatePosition(from: CGPoint(x: 0.0, y: 44.0), to: .zero, duration: 0.3, timingFunction: kCAMediaTimingFunctionSpring, additive: true)
view.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2)
@ -546,16 +533,6 @@ final class MediaEditorScreenComponent: Component {
transition.setScale(view: view, scale: 0.1)
}
if let view = self.settingsButton.view {
transition.setAlpha(view: view, alpha: 0.0)
transition.setScale(view: view, scale: 0.1)
}
if let view = self.privacyButton.view {
transition.setAlpha(view: view, alpha: 0.0)
transition.setScale(view: view, scale: 0.1)
}
if let view = self.scrubber.view {
view.layer.animatePosition(from: .zero, to: CGPoint(x: 0.0, y: 44.0), duration: 0.3, timingFunction: kCAMediaTimingFunctionSpring, removeOnCompletion: false, additive: true)
view.layer.animateAlpha(from: view.alpha, to: 0.0, duration: 0.2, removeOnCompletion: false)
@ -673,12 +650,7 @@ final class MediaEditorScreenComponent: Component {
self.setupIfNeeded()
let isTablet: Bool
if case .regular = environment.metrics.widthClass {
isTablet = true
} else {
isTablet = false
}
let isTablet = environment.metrics.isTablet
let openDrawing = component.openDrawing
let openTools = component.openTools
@ -745,11 +717,12 @@ final class MediaEditorScreenComponent: Component {
let doneButtonSize = self.doneButton.update(
transition: transition,
component: AnyComponent(Button(
content: AnyComponent(DoneButtonComponent(
component: AnyComponent(PlainButtonComponent(
content: AnyComponent(DoneButtonContentComponent(
backgroundColor: UIColor(rgb: 0x007aff),
icon: UIImage(bundleImageName: "Media Editor/Next")!,
title: doneButtonTitle.uppercased())),
effectAlignment: .center,
action: {
guard let controller = environment.controller() as? MediaEditorScreen else {
return
@ -1282,70 +1255,9 @@ final class MediaEditorScreenComponent: Component {
transition.setAlpha(view: inputPanelView, alpha: isEditingTextEntity || component.isDisplayingTool || component.isDismissing || component.isInteractingWithEntities ? 0.0 : 1.0)
}
let additionalPeersCount = component.privacy.privacy.additionallyIncludePeers.count
var privacyText: String
switch component.privacy.privacy.base {
case .everyone:
privacyText = environment.strings.Story_ContextPrivacy_LabelEveryone
case .closeFriends:
privacyText = environment.strings.Story_ContextPrivacy_LabelCloseFriends
case .contacts:
if additionalPeersCount > 0 {
privacyText = environment.strings.Story_ContextPrivacy_LabelContactsExcept("\(additionalPeersCount)").string
} else {
privacyText = environment.strings.Story_ContextPrivacy_LabelContacts
}
case .nobody:
if additionalPeersCount > 0 {
privacyText = environment.strings.Story_ContextPrivacy_LabelOnlySelected(Int32(additionalPeersCount))
} else {
privacyText = environment.strings.Story_ContextPrivacy_LabelOnlyMe
}
}
let displayTopButtons = !(self.inputPanelExternalState.isEditing || isEditingTextEntity || component.isDisplayingTool)
let privacyButtonSize = self.privacyButton.update(
transition: transition,
component: AnyComponent(Button(
content: AnyComponent(
PrivacyButtonComponent(
backgroundColor: isTablet ? UIColor(rgb: 0x303030, alpha: 0.5) : UIColor(white: 0.0, alpha: 0.5),
icon: UIImage(bundleImageName: "Media Editor/Recipient")!,
text: privacyText
)
),
action: {
if let controller = environment.controller() as? MediaEditorScreen {
controller.openPrivacySettings()
}
}
).tagged(privacyButtonTag)),
environment: {},
containerSize: CGSize(width: 44.0, height: 44.0)
)
let privacyButtonFrame: CGRect
if isTablet {
privacyButtonFrame = CGRect(
origin: CGPoint(x: availableSize.width - buttonSideInset - doneButtonSize.width - privacyButtonSize.width - 24.0, y: availableSize.height - environment.safeInsets.bottom + buttonBottomInset + 1.0),
size: privacyButtonSize
)
} else {
privacyButtonFrame = CGRect(
origin: CGPoint(x: 16.0, y: environment.safeInsets.top + 20.0),
size: privacyButtonSize
)
}
if let privacyButtonView = self.privacyButton.view {
if privacyButtonView.superview == nil {
//self.addSubview(privacyButtonView)
}
transition.setPosition(view: privacyButtonView, position: privacyButtonFrame.center)
transition.setBounds(view: privacyButtonView, bounds: CGRect(origin: .zero, size: privacyButtonFrame.size))
transition.setScale(view: privacyButtonView, scale: displayTopButtons ? 1.0 : 0.01)
transition.setAlpha(view: privacyButtonView, alpha: displayTopButtons && !component.isDismissing && !component.isInteractingWithEntities ? 1.0 : 0.0)
}
let saveContentComponent: AnyComponentWithIdentity<Empty>
if component.hasAppeared {
saveContentComponent = AnyComponentWithIdentity(
@ -2747,10 +2659,8 @@ public final class MediaEditorScreen: ViewController, UIDropInteractionDelegate
if let context = context {
let path = UIBezierPath(roundedRect: rect, cornerRadius: cornerRadius)
context.addPath(path.cgPath)
context.clip()
image.draw(in: rect)
}
@ -3814,8 +3724,6 @@ public final class MediaEditorScreen: ViewController, UIDropInteractionDelegate
duration = durationValue
}
let _ = additionalPath
firstFrame = Signal<(UIImage?, UIImage?), NoError> { subscriber in
let avAsset = AVURLAsset(url: URL(fileURLWithPath: path))
let avAssetGenerator = AVAssetImageGenerator(asset: avAsset)
@ -4135,10 +4043,6 @@ public final class MediaEditorScreen: ViewController, UIDropInteractionDelegate
}
}
func requestSettings() {
}
fileprivate func cancelVideoExport() {
if let videoExport = self.videoExport {
self.previousSavedValues = nil
@ -4213,80 +4117,7 @@ public final class MediaEditorScreen: ViewController, UIDropInteractionDelegate
}
}
final class PrivacyButtonComponent: CombinedComponent {
let backgroundColor: UIColor
let icon: UIImage
let text: String
init(
backgroundColor: UIColor,
icon: UIImage,
text: String
) {
self.backgroundColor = backgroundColor
self.icon = icon
self.text = text
}
static func ==(lhs: PrivacyButtonComponent, rhs: PrivacyButtonComponent) -> Bool {
if lhs.backgroundColor != rhs.backgroundColor {
return false
}
if lhs.text != rhs.text {
return false
}
return true
}
static var body: Body {
let background = Child(BlurredBackgroundComponent.self)
let icon = Child(Image.self)
let text = Child(Text.self)
return { context in
let icon = icon.update(
component: Image(image: context.component.icon, size: CGSize(width: 9.0, height: 11.0)),
availableSize: CGSize(width: 180.0, height: 100.0),
transition: .immediate
)
let text = text.update(
component: Text(
text: context.component.text,
font: Font.medium(14.0),
color: .white
),
availableSize: CGSize(width: 180.0, height: 100.0),
transition: .immediate
)
let backgroundSize = CGSize(width: text.size.width + 38.0, height: 30.0)
let background = background.update(
component: BlurredBackgroundComponent(color: context.component.backgroundColor),
availableSize: backgroundSize,
transition: .immediate
)
context.add(background
.position(CGPoint(x: backgroundSize.width / 2.0, y: backgroundSize.height / 2.0))
.cornerRadius(min(backgroundSize.width, backgroundSize.height) / 2.0)
.clipsToBounds(true)
)
context.add(icon
.position(CGPoint(x: 16.0, y: backgroundSize.height / 2.0))
)
context.add(text
.position(CGPoint(x: backgroundSize.width / 2.0 + 7.0, y: backgroundSize.height / 2.0))
)
return backgroundSize
}
}
}
final class DoneButtonComponent: CombinedComponent {
final class DoneButtonContentComponent: CombinedComponent {
let backgroundColor: UIColor
let icon: UIImage
let title: String?
@ -4301,7 +4132,7 @@ final class DoneButtonComponent: CombinedComponent {
self.title = title
}
static func ==(lhs: DoneButtonComponent, rhs: DoneButtonComponent) -> Bool {
static func ==(lhs: DoneButtonContentComponent, rhs: DoneButtonContentComponent) -> Bool {
if lhs.backgroundColor != rhs.backgroundColor {
return false
}

View File

@ -383,8 +383,6 @@ public final class SaveProgressScreenComponent: Component {
}
}
private let storyDimensions = CGSize(width: 1080.0, height: 1920.0)
public final class SaveProgressScreen: ViewController {
fileprivate final class Node: ViewControllerTracingNode, UIGestureRecognizerDelegate {
private weak var controller: SaveProgressScreen?