added MTMathImage - draw latex image offscreen.
This commit is contained in:
@@ -18,6 +18,7 @@ public typealias MTBezierPath = UIBezierPath
|
||||
public typealias MTLabel = UILabel
|
||||
public typealias MTEdgeInsets = UIEdgeInsets
|
||||
public typealias MTRect = CGRect
|
||||
public typealias MTImage = UIImage
|
||||
|
||||
let MTEdgeInsetsZero = UIEdgeInsets.zero
|
||||
func MTGraphicsGetCurrentContext() -> CGContext? { UIGraphicsGetCurrentContext() }
|
||||
@@ -31,6 +32,7 @@ public typealias MTColor = NSColor
|
||||
public typealias MTBezierPath = NSBezierPath
|
||||
public typealias MTEdgeInsets = NSEdgeInsets
|
||||
public typealias MTRect = NSRect
|
||||
public typealias MTImage = NSImage
|
||||
|
||||
let MTEdgeInsetsZero = NSEdgeInsets.init(top: 0, left: 0, bottom: 0, right: 0)
|
||||
func MTGraphicsGetCurrentContext() -> CGContext? { NSGraphicsContext.current?.cgContext }
|
||||
|
||||
@@ -11,17 +11,16 @@ import Foundation
|
||||
|
||||
public class MTFontManager {
|
||||
|
||||
static public private(set) var manager:MTFontManager! = nil
|
||||
static public private(set) var manager: MTFontManager = {
|
||||
MTFontManager()
|
||||
}()
|
||||
|
||||
let kDefaultFontSize = CGFloat(20)
|
||||
|
||||
static var fontManager : MTFontManager {
|
||||
if manager == nil {
|
||||
manager = MTFontManager()
|
||||
}
|
||||
return manager!
|
||||
return manager
|
||||
}
|
||||
|
||||
|
||||
public init() { }
|
||||
|
||||
var nameToFontMap = [String: MTFont]()
|
||||
|
||||
111
Sources/SwiftMath/MathRender/MTMathImage.swift
Normal file
111
Sources/SwiftMath/MathRender/MTMathImage.swift
Normal file
@@ -0,0 +1,111 @@
|
||||
//
|
||||
// File.swift
|
||||
//
|
||||
//
|
||||
// Created by Peter Tang on 12/9/2023.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
#if os(iOS)
|
||||
import UIKit
|
||||
#endif
|
||||
|
||||
#if os(macOS)
|
||||
import AppKit
|
||||
#endif
|
||||
|
||||
public class MTMathImage {
|
||||
public var font: MTFont? = nil
|
||||
public let fontSize: CGFloat
|
||||
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.fontSize = fontSize
|
||||
self.textColor = textColor
|
||||
self.labelMode = labelMode
|
||||
self.textAlignment = textAlignment
|
||||
}
|
||||
}
|
||||
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)
|
||||
}
|
||||
if font == nil {
|
||||
self.font = MTFontManager.fontManager.defaultFont
|
||||
}
|
||||
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)
|
||||
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: true) { 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
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user