mirror of
https://github.com/TelegramMessenger/Telegram-iOS.git
synced 2026-05-21 18:20:41 +00:00
118 lines
4.2 KiB
Swift
Executable File
118 lines
4.2 KiB
Swift
Executable File
//
|
|
// File.swift
|
|
//
|
|
//
|
|
// Created by Peter Tang on 12/9/2023.
|
|
//
|
|
|
|
import Foundation
|
|
|
|
#if os(iOS) || os(visionOS)
|
|
import UIKit
|
|
#endif
|
|
|
|
#if os(macOS)
|
|
import AppKit
|
|
#endif
|
|
|
|
public class MTMathImage {
|
|
public var font: MTFont? = MTFontManager.fontManager.defaultFont
|
|
public var fontSize:CGFloat {
|
|
set {
|
|
_fontSize = newValue
|
|
let font = font?.copy(withSize: newValue)
|
|
self.font = font // also forces an update
|
|
}
|
|
get { _fontSize }
|
|
}
|
|
private var _fontSize:CGFloat = 0
|
|
public let textColor: MTColor
|
|
|
|
public let labelMode: MTMathUILabelMode
|
|
public let textAlignment: MTTextAlignment
|
|
|
|
public var contentInsets: MTEdgeInsets = MTEdgeInsetsZero
|
|
|
|
public let latex: String
|
|
private(set) var intrinsicContentSize = CGSize.zero
|
|
|
|
public init(latex: String, fontSize: CGFloat, textColor: MTColor, labelMode: MTMathUILabelMode = .display, textAlignment: MTTextAlignment = .center) {
|
|
self.latex = latex
|
|
self.textColor = textColor
|
|
self.labelMode = labelMode
|
|
self.textAlignment = textAlignment
|
|
self.fontSize = fontSize
|
|
}
|
|
}
|
|
extension MTMathImage {
|
|
public var currentStyle: MTLineStyle {
|
|
switch labelMode {
|
|
case .display: return .display
|
|
case .text: return .text
|
|
}
|
|
}
|
|
private func intrinsicContentSize(_ displayList: MTMathListDisplay) -> CGSize {
|
|
CGSize(width: displayList.width + contentInsets.left + contentInsets.right,
|
|
height: displayList.ascent + displayList.descent + contentInsets.top + contentInsets.bottom)
|
|
}
|
|
public func asImage() -> (NSError?, MTImage?) {
|
|
func layoutImage(size: CGSize, displayList: MTMathListDisplay) {
|
|
var textX = CGFloat(0)
|
|
switch self.textAlignment {
|
|
case .left: textX = contentInsets.left
|
|
case .center: textX = (size.width - contentInsets.left - contentInsets.right - displayList.width) / 2 + contentInsets.left
|
|
case .right: textX = size.width - displayList.width - contentInsets.right
|
|
}
|
|
let availableHeight = size.height - contentInsets.bottom - contentInsets.top
|
|
|
|
// center things vertically
|
|
var height = displayList.ascent + displayList.descent
|
|
if height < fontSize/2 {
|
|
height = fontSize/2 // set height to half the font size
|
|
}
|
|
let textY = (availableHeight - height) / 2 + displayList.descent + contentInsets.bottom
|
|
displayList.position = CGPoint(x: textX, y: textY)
|
|
}
|
|
|
|
var error: NSError?
|
|
guard let mathList = MTMathListBuilder.build(fromString: latex, error: &error), error == nil,
|
|
let displayList = MTTypesetter.createLineForMathList(mathList, font: font, style: currentStyle) else {
|
|
return (error, nil)
|
|
}
|
|
|
|
intrinsicContentSize = intrinsicContentSize(displayList)
|
|
displayList.textColor = textColor
|
|
|
|
let size = intrinsicContentSize
|
|
layoutImage(size: size, displayList: displayList)
|
|
|
|
#if os(iOS) || os(visionOS)
|
|
let renderer = UIGraphicsImageRenderer(size: size)
|
|
let image = renderer.image { rendererContext in
|
|
rendererContext.cgContext.saveGState()
|
|
rendererContext.cgContext.concatenate(.flippedVertically(size.height))
|
|
displayList.draw(rendererContext.cgContext)
|
|
rendererContext.cgContext.restoreGState()
|
|
}
|
|
return (nil, image)
|
|
#endif
|
|
#if os(macOS)
|
|
let image = NSImage(size: size, flipped: false) { bounds in
|
|
guard let context = NSGraphicsContext.current?.cgContext else { return false }
|
|
context.saveGState()
|
|
displayList.draw(context)
|
|
context.restoreGState()
|
|
return true
|
|
}
|
|
return (nil, image)
|
|
#endif
|
|
}
|
|
}
|
|
private extension CGAffineTransform {
|
|
static func flippedVertically(_ height: CGFloat) -> CGAffineTransform {
|
|
var transform = CGAffineTransform(scaleX: 1, y: -1)
|
|
transform = transform.translatedBy(x: 0, y: -height)
|
|
return transform
|
|
}
|
|
}
|